From 81265d2c2a16dd651894d8151ae0045bf4f64371 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 8 Aug 2022 08:39:13 -0700 Subject: [PATCH] Add support for source fallback with scaled float field type (#89053) This change adds source fallback support for scaled float. This uses the already existing class SourceValueFetcherSortedDoubleIndexFieldData. --- docs/changelog/89053.yaml | 5 ++ .../test/painless/50_script_doc_values.yml | 58 +++++++++++++++++++ .../mapper/extras/ScaledFloatFieldMapper.java | 48 ++++++++++++--- 3 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 docs/changelog/89053.yaml diff --git a/docs/changelog/89053.yaml b/docs/changelog/89053.yaml new file mode 100644 index 0000000000000..e8ee495cc0db1 --- /dev/null +++ b/docs/changelog/89053.yaml @@ -0,0 +1,5 @@ +pr: 89053 +summary: Add support for source fallback with scaled float field type +area: Mapping +type: enhancement +issues: [] diff --git a/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml index 85b5dc4680b6e..dd2187673134a 100644 --- a/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml +++ b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml @@ -66,6 +66,10 @@ setup: scaled_float: type: scaled_float scaling_factor: 100 + scaled_float_no_doc_values: + type: scaled_float + scaling_factor: 100 + doc_values: false token_count: type: token_count analyzer: standard @@ -105,6 +109,7 @@ setup: half_float: 3.140625 half_float_no_doc_values: 3.140625 scaled_float: 3.14 + scaled_float_no_doc_values: 3.14 token_count: count all these words please - do: @@ -144,6 +149,7 @@ setup: half_float: [1.123, 2.234] half_float_no_doc_values: [2.234, 1.123] scaled_float: [-3.5, 2.5] + scaled_float_no_doc_values: [2.5, -3.5] - do: @@ -2605,6 +2611,58 @@ setup: source: "doc['scaled_float'].value" - match: { hits.hits.0.fields.field.0: 3.14 } +--- +"scaled_float_no_doc_values": + - do: + catch: bad_request + search: + rest_total_hits_as_int: true + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "doc['scaled_float_no_doc_values'].get(0)" + - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" } + + - do: + catch: bad_request + search: + rest_total_hits_as_int: true + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "doc['scaled_float_no_doc_values'].value" + - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" } + + - do: + search: + rest_total_hits_as_int: true + body: + sort: [ { rank: asc } ] + script_fields: + field: + script: + source: "/* avoid stash */ $('scaled_float_no_doc_values', 0.0)" + - match: { hits.hits.0.fields.field.0: 3.14 } + - match: { hits.hits.1.fields.field.0: 0.0 } + - match: { hits.hits.2.fields.field.0: -3.5 } + + - do: + search: + rest_total_hits_as_int: true + body: + sort: [ { rank: asc } ] + script_fields: + field: + script: + source: "field('scaled_float_no_doc_values').get(1, 0.0)" + - match: { hits.hits.0.fields.field.0: 0.0 } + - match: { hits.hits.1.fields.field.0: 0.0 } + - match: { hits.hits.2.fields.field.0: 2.5 } + --- "token_count": - do: diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java index 40dc7ebd390af..84c51fe0ab6c1 100644 --- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java +++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java @@ -27,6 +27,7 @@ import org.elasticsearch.index.fielddata.NumericDoubleValues; import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortedNumericDoubleValues; +import org.elasticsearch.index.fielddata.SourceValueFetcherSortedDoubleIndexFieldData; import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData; import org.elasticsearch.index.mapper.DocumentParserContext; import org.elasticsearch.index.mapper.FieldMapper; @@ -43,7 +44,9 @@ import org.elasticsearch.script.field.ScaledFloatDocValuesField; import org.elasticsearch.script.field.ToScriptFieldFactory; import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.support.CoreValuesSourceType; import org.elasticsearch.search.aggregations.support.ValuesSourceType; +import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParser.Token; @@ -57,6 +60,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; /** A {@link FieldMapper} for scaled floats. Values are internally multiplied * by a scaling factor and rounded to the closest long. */ @@ -276,15 +280,37 @@ public Query rangeQuery( @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { - failIfNoDocValues(); - return (cache, breakerService) -> { - final IndexNumericFieldData scaledValues = new SortedNumericIndexFieldData.Builder( + FielddataOperation operation = fieldDataContext.fielddataOperation(); + + if (operation == FielddataOperation.SEARCH) { + failIfNoDocValues(); + } + + if ((operation == FielddataOperation.SEARCH || operation == FielddataOperation.SCRIPT) && hasDocValues()) { + return (cache, breakerService) -> { + final IndexNumericFieldData scaledValues = new SortedNumericIndexFieldData.Builder( + name(), + IndexNumericFieldData.NumericType.LONG, + (dv, n) -> { throw new UnsupportedOperationException(); } + ).build(cache, breakerService); + return new ScaledFloatIndexFieldData(scaledValues, scalingFactor, ScaledFloatDocValuesField::new); + }; + } + + if (operation == FielddataOperation.SCRIPT) { + SearchLookup searchLookup = fieldDataContext.lookupSupplier().get(); + Set sourcePaths = fieldDataContext.sourcePathsLookup().apply(name()); + + return new SourceValueFetcherSortedDoubleIndexFieldData.Builder( name(), - IndexNumericFieldData.NumericType.LONG, - (dv, n) -> { throw new UnsupportedOperationException(); } - ).build(cache, breakerService); - return new ScaledFloatIndexFieldData(scaledValues, scalingFactor, ScaledFloatDocValuesField::new); - }; + CoreValuesSourceType.NUMERIC, + sourceValueFetcher(sourcePaths), + searchLookup.source(), + ScaledFloatDocValuesField::new + ); + } + + throw new IllegalStateException("unknown field data type [" + operation.name() + "]"); } @Override @@ -292,7 +318,11 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format) if (format != null) { throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats."); } - return new SourceValueFetcher(name(), context) { + return sourceValueFetcher(context.isSourceEnabled() ? context.sourcePath(name()) : Collections.emptySet()); + } + + private SourceValueFetcher sourceValueFetcher(Set sourcePaths) { + return new SourceValueFetcher(sourcePaths, nullValue) { @Override protected Double parseSourceValue(Object value) { double doubleValue;