|
@@ -18,14 +18,11 @@
|
|
|
*/
|
|
|
package org.elasticsearch.search.aggregations.support;
|
|
|
|
|
|
-import org.apache.lucene.util.BytesRef;
|
|
|
import org.elasticsearch.common.Nullable;
|
|
|
-import org.elasticsearch.common.geo.GeoPoint;
|
|
|
import org.elasticsearch.common.time.DateFormatter;
|
|
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
|
|
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
|
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
|
|
-import org.elasticsearch.index.fielddata.IndexOrdinalsFieldData;
|
|
|
import org.elasticsearch.index.mapper.DateFieldMapper;
|
|
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
|
|
import org.elasticsearch.index.mapper.RangeFieldMapper;
|
|
@@ -33,7 +30,6 @@ import org.elasticsearch.index.query.QueryShardContext;
|
|
|
import org.elasticsearch.script.AggregationScript;
|
|
|
import org.elasticsearch.script.Script;
|
|
|
import org.elasticsearch.search.DocValueFormat;
|
|
|
-import org.elasticsearch.search.aggregations.AggregationExecutionException;
|
|
|
|
|
|
import java.time.ZoneId;
|
|
|
import java.time.ZoneOffset;
|
|
@@ -55,7 +51,7 @@ public class ValuesSourceConfig<VS extends ValuesSource> {
|
|
|
Object missing,
|
|
|
ZoneId timeZone,
|
|
|
String format) {
|
|
|
- return resolve(context, valueType, field, script, missing, timeZone, format, s -> ValuesSourceType.BYTES);
|
|
|
+ return resolve(context, valueType, field, script, missing, timeZone, format, s -> CoreValuesSourceType.BYTES);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -73,12 +69,12 @@ public class ValuesSourceConfig<VS extends ValuesSource> {
|
|
|
|
|
|
if (field == null) {
|
|
|
if (script == null) {
|
|
|
- ValuesSourceConfig<VS> config = new ValuesSourceConfig<>(ValuesSourceType.ANY);
|
|
|
+ ValuesSourceConfig<VS> config = new ValuesSourceConfig<>(CoreValuesSourceType.ANY);
|
|
|
config.format(resolveFormat(null, valueType, timeZone));
|
|
|
return config;
|
|
|
}
|
|
|
- ValuesSourceType valuesSourceType = valueType != null ? valueType.getValuesSourceType() : ValuesSourceType.ANY;
|
|
|
- if (valuesSourceType == ValuesSourceType.ANY) {
|
|
|
+ ValuesSourceType valuesSourceType = valueType != null ? valueType.getValuesSourceType() : CoreValuesSourceType.ANY;
|
|
|
+ if (valuesSourceType == CoreValuesSourceType.ANY) {
|
|
|
// the specific value source type is undefined, but for scripts,
|
|
|
// we need to have a specific value source
|
|
|
// type to know how to handle the script values, so we fallback
|
|
@@ -96,7 +92,7 @@ public class ValuesSourceConfig<VS extends ValuesSource> {
|
|
|
|
|
|
MappedFieldType fieldType = context.fieldMapper(field);
|
|
|
if (fieldType == null) {
|
|
|
- ValuesSourceType valuesSourceType = valueType != null ? valueType.getValuesSourceType() : ValuesSourceType.ANY;
|
|
|
+ ValuesSourceType valuesSourceType = valueType != null ? valueType.getValuesSourceType() : CoreValuesSourceType.ANY;
|
|
|
ValuesSourceConfig<VS> config = new ValuesSourceConfig<>(valuesSourceType);
|
|
|
config.missing(missing);
|
|
|
config.timezone(timeZone);
|
|
@@ -113,14 +109,14 @@ public class ValuesSourceConfig<VS extends ValuesSource> {
|
|
|
|
|
|
ValuesSourceConfig<VS> config;
|
|
|
if (indexFieldData instanceof IndexNumericFieldData) {
|
|
|
- config = new ValuesSourceConfig<>(ValuesSourceType.NUMERIC);
|
|
|
+ config = new ValuesSourceConfig<>(CoreValuesSourceType.NUMERIC);
|
|
|
} else if (indexFieldData instanceof IndexGeoPointFieldData) {
|
|
|
- config = new ValuesSourceConfig<>(ValuesSourceType.GEOPOINT);
|
|
|
+ config = new ValuesSourceConfig<>(CoreValuesSourceType.GEOPOINT);
|
|
|
} else if (fieldType instanceof RangeFieldMapper.RangeFieldType) {
|
|
|
- config = new ValuesSourceConfig<>(ValuesSourceType.RANGE);
|
|
|
+ config = new ValuesSourceConfig<>(CoreValuesSourceType.RANGE);
|
|
|
} else {
|
|
|
if (valueType == null) {
|
|
|
- config = new ValuesSourceConfig<>(ValuesSourceType.BYTES);
|
|
|
+ config = new ValuesSourceConfig<>(CoreValuesSourceType.BYTES);
|
|
|
} else {
|
|
|
config = new ValuesSourceConfig<>(valueType.getValuesSourceType());
|
|
|
}
|
|
@@ -262,126 +258,30 @@ public class ValuesSourceConfig<VS extends ValuesSource> {
|
|
|
if (missing() == null) {
|
|
|
// otherwise we will have values because of the missing value
|
|
|
vs = null;
|
|
|
- } else if (valueSourceType() == ValuesSourceType.NUMERIC) {
|
|
|
- vs = (VS) ValuesSource.Numeric.EMPTY;
|
|
|
- } else if (valueSourceType() == ValuesSourceType.GEOPOINT) {
|
|
|
- vs = (VS) ValuesSource.GeoPoint.EMPTY;
|
|
|
- } else if (valueSourceType() == ValuesSourceType.BYTES) {
|
|
|
- vs = (VS) ValuesSource.Bytes.WithOrdinals.EMPTY;
|
|
|
- } else if (valueSourceType() == ValuesSourceType.ANY) {
|
|
|
+ } else if (valueSourceType() == CoreValuesSourceType.ANY) {
|
|
|
+ // TODO: Clean up special cases around CoreValuesSourceType.ANY
|
|
|
vs = (VS) resolveMissingAny.apply(missing());
|
|
|
} else {
|
|
|
- throw new IllegalArgumentException("Can't deal with unmapped ValuesSource type " + valueSourceType());
|
|
|
+ vs = (VS) valueSourceType().getEmpty();
|
|
|
}
|
|
|
} else {
|
|
|
- vs = originalValuesSource();
|
|
|
- }
|
|
|
-
|
|
|
- if (missing() == null) {
|
|
|
- return vs;
|
|
|
- }
|
|
|
-
|
|
|
- if (vs instanceof ValuesSource.Bytes) {
|
|
|
- final BytesRef missing = format.parseBytesRef(missing().toString());
|
|
|
- if (vs instanceof ValuesSource.Bytes.WithOrdinals) {
|
|
|
- return (VS) MissingValues.replaceMissing((ValuesSource.Bytes.WithOrdinals) vs, missing);
|
|
|
+ if (fieldContext() == null) {
|
|
|
+ vs = (VS) valueSourceType().getScript(script(), scriptValueType());
|
|
|
} else {
|
|
|
- return (VS) MissingValues.replaceMissing((ValuesSource.Bytes) vs, missing);
|
|
|
+ if (valueSourceType() == CoreValuesSourceType.ANY) {
|
|
|
+ // TODO: Clean up special cases around CoreValuesSourceType.ANY
|
|
|
+ // falling back to bytes values
|
|
|
+ vs = (VS) CoreValuesSourceType.BYTES.getField(fieldContext(), script());
|
|
|
+ } else {
|
|
|
+ // TODO: Better docs for Scripts vs Scripted Fields
|
|
|
+ vs = (VS) valueSourceType().getField(fieldContext(), script());
|
|
|
+ }
|
|
|
}
|
|
|
- } else if (vs instanceof ValuesSource.Numeric) {
|
|
|
- Number missing = format.parseDouble(missing().toString(), false, context::nowInMillis);
|
|
|
- return (VS) MissingValues.replaceMissing((ValuesSource.Numeric) vs, missing);
|
|
|
- } else if (vs instanceof ValuesSource.GeoPoint) {
|
|
|
- // TODO: also support the structured formats of geo points
|
|
|
- final GeoPoint missing = new GeoPoint(missing().toString());
|
|
|
- return (VS) MissingValues.replaceMissing((ValuesSource.GeoPoint) vs, missing);
|
|
|
- } else {
|
|
|
- // Should not happen
|
|
|
- throw new IllegalArgumentException("Can't apply missing values on a " + vs.getClass());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Return the original values source, before we apply `missing`.
|
|
|
- */
|
|
|
- private VS originalValuesSource() {
|
|
|
- if (fieldContext() == null) {
|
|
|
- if (valueSourceType() == ValuesSourceType.NUMERIC) {
|
|
|
- return (VS) numericScript();
|
|
|
- }
|
|
|
- if (valueSourceType() == ValuesSourceType.BYTES) {
|
|
|
- return (VS) bytesScript();
|
|
|
- }
|
|
|
- throw new AggregationExecutionException("value source of type [" + valueSourceType().name()
|
|
|
- + "] is not supported by scripts");
|
|
|
- }
|
|
|
-
|
|
|
- if (valueSourceType() == ValuesSourceType.NUMERIC) {
|
|
|
- return (VS) numericField();
|
|
|
- }
|
|
|
- if (valueSourceType() == ValuesSourceType.GEOPOINT) {
|
|
|
- return (VS) geoPointField();
|
|
|
- }
|
|
|
- if (valueSourceType() == ValuesSourceType.RANGE) {
|
|
|
- return (VS) rangeField();
|
|
|
- }
|
|
|
- // falling back to bytes values
|
|
|
- return (VS) bytesField();
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource.Numeric numericScript() {
|
|
|
- return new ValuesSource.Numeric.Script(script(), scriptValueType());
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource.Numeric numericField() {
|
|
|
-
|
|
|
- if (!(fieldContext().indexFieldData() instanceof IndexNumericFieldData)) {
|
|
|
- throw new IllegalArgumentException("Expected numeric type on field [" + fieldContext().field() +
|
|
|
- "], but got [" + fieldContext().fieldType().typeName() + "]");
|
|
|
}
|
|
|
|
|
|
- ValuesSource.Numeric dataSource = new ValuesSource.Numeric.FieldData((IndexNumericFieldData)fieldContext().indexFieldData());
|
|
|
- if (script() != null) {
|
|
|
- dataSource = new ValuesSource.Numeric.WithScript(dataSource, script());
|
|
|
- }
|
|
|
- return dataSource;
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource bytesField() {
|
|
|
- final IndexFieldData<?> indexFieldData = fieldContext().indexFieldData();
|
|
|
- ValuesSource dataSource;
|
|
|
- if (indexFieldData instanceof IndexOrdinalsFieldData) {
|
|
|
- dataSource = new ValuesSource.Bytes.WithOrdinals.FieldData((IndexOrdinalsFieldData) indexFieldData);
|
|
|
- } else {
|
|
|
- dataSource = new ValuesSource.Bytes.FieldData(indexFieldData);
|
|
|
- }
|
|
|
- if (script() != null) {
|
|
|
- dataSource = new ValuesSource.WithScript(dataSource, script());
|
|
|
- }
|
|
|
- return dataSource;
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource.Bytes bytesScript() {
|
|
|
- return new ValuesSource.Bytes.Script(script());
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource.GeoPoint geoPointField() {
|
|
|
-
|
|
|
- if (!(fieldContext().indexFieldData() instanceof IndexGeoPointFieldData)) {
|
|
|
- throw new IllegalArgumentException("Expected geo_point type on field [" + fieldContext().field() +
|
|
|
- "], but got [" + fieldContext().fieldType().typeName() + "]");
|
|
|
- }
|
|
|
-
|
|
|
- return new ValuesSource.GeoPoint.Fielddata((IndexGeoPointFieldData) fieldContext().indexFieldData());
|
|
|
- }
|
|
|
-
|
|
|
- private ValuesSource rangeField() {
|
|
|
- MappedFieldType fieldType = fieldContext.fieldType();
|
|
|
-
|
|
|
- if (fieldType instanceof RangeFieldMapper.RangeFieldType == false) {
|
|
|
- throw new IllegalStateException("Asked for range ValuesSource, but field is of type " + fieldType.name());
|
|
|
+ if (missing() == null) {
|
|
|
+ return vs;
|
|
|
}
|
|
|
- RangeFieldMapper.RangeFieldType rangeFieldType = (RangeFieldMapper.RangeFieldType)fieldType;
|
|
|
- return new ValuesSource.Range(fieldContext().indexFieldData(), rangeFieldType.rangeType());
|
|
|
+ return (VS) valueSourceType().replaceMissing(vs, missing, format, context::nowInMillis);
|
|
|
}
|
|
|
}
|