diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java index ed1ce9076de50..d61c3c6a429fb 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java @@ -88,6 +88,7 @@ public class ScriptScoreBenchmark { private final SearchLookup lookup = new SearchLookup( fieldTypes::get, (mft, lookup, fdo) -> mft.fielddataBuilder(FieldDataContext.noRuntimeFields("benchmark")).build(fieldDataCache, breakerService), + (mft, lookup, fdo) -> mft.isFielddataSupported(FieldDataContext.noRuntimeFields("benchmark")), SourceProvider.fromStoredFields() ); diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/QueryParserHelperBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/QueryParserHelperBenchmark.java index 6aacf319e6b8b..890f45539f9c2 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/QueryParserHelperBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/QueryParserHelperBenchmark.java @@ -28,7 +28,10 @@ import org.elasticsearch.core.IOUtils; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexVersion; +import org.elasticsearch.index.fielddata.FieldDataContext; +import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldDataCache; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperRegistry; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.ParsedDocument; @@ -135,12 +138,17 @@ public void expand() { protected SearchExecutionContext buildSearchExecutionContext() { final SimilarityService similarityService = new SimilarityService(mapperService.getIndexSettings(), null, Map.of()); final long nowInMillis = 1; - return new SearchExecutionContext( - 0, - 0, - mapperService.getIndexSettings(), - null, - (ft, fdc) -> ft.fielddataBuilder(fdc).build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()), + return new SearchExecutionContext(0, 0, mapperService.getIndexSettings(), null, new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext context) { + return fieldType.isFielddataSupported(context); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext context) { + return fieldType.fielddataBuilder(context).build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()); + } + }, mapperService, mapperService.mappingLookup(), similarityService, diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionFieldScriptTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionFieldScriptTests.java index e573d32f7b6c2..ab779e163b938 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionFieldScriptTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionFieldScriptTests.java @@ -54,6 +54,7 @@ public void setUp() throws Exception { lookup = new SearchLookup( field -> field.equals("field") ? fieldType : null, (ignored, _lookup, fdt) -> fieldData, + (ignored, _lookup, fdt) -> true, (ctx, doc) -> Source.empty(XContentType.JSON) ); } diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionNumberSortScriptTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionNumberSortScriptTests.java index eedd80bf6d295..c6e97b3f7a4d1 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionNumberSortScriptTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionNumberSortScriptTests.java @@ -55,6 +55,7 @@ public void setUp() throws Exception { lookup = new SearchLookup( field -> field.equals("field") ? fieldType : null, (ignored, _lookup, fdt) -> fieldData, + (ignored, _lookup, fdt) -> true, (ctx, doc) -> Source.empty(XContentType.JSON) ); } diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTermsSetQueryTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTermsSetQueryTests.java index d88b2d67e663a..f27540dbe43a8 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTermsSetQueryTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTermsSetQueryTests.java @@ -54,6 +54,7 @@ public void setUp() throws Exception { lookup = new SearchLookup( field -> field.equals("field") ? fieldType : null, (ignored, _lookup, fdt) -> fieldData, + (ignored, _lookup, fdt) -> true, (ctx, doc) -> Source.empty(XContentType.JSON) ); } 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 ee6803d809087..5a96655249fa1 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 @@ -100,6 +100,7 @@ setup: rank: 1 boolean: true boolean_no_doc_values: true + boolean_not_mapped: true date: 2017-01-01T12:11:12 date_no_doc_values: 2017-01-01T12:11:12 nanos: 2015-01-01T12:10:30.123456789Z @@ -412,6 +413,66 @@ boolean: source: "field('boolean').size()" - match: { hits.hits.0.fields.field.0: 0 } +--- +boolean_not_existing: + - do: + catch: bad_request + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "doc['boolean_not_existing'].value" + - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" } + + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('boolean_not_existing').empty" + - match: { hits.hits.0.fields.field.0: true } + + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('boolean_not_existing').get(false)" + - match: { hits.hits.0.fields.field.0: false } + +--- +boolean_not_mapped: + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "doc['boolean_not_mapped'].value" + - match: { hits.hits.0.fields.field.0: true } + + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('boolean_not_mapped').get(false)" + - match: { hits.hits.0.fields.field.0: true } + --- boolean_no_doc_values: - do: @@ -449,6 +510,28 @@ boolean_no_doc_values: source: "field('boolean_no_doc_values').get(false)" - match: { hits.hits.0.fields.field.0: true } + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('boolean_no_doc_values').empty" + - match: { hits.hits.0.fields.field.0: false } + + - do: + search: + index: test + body: + query: { term: { _id: "2" } } + script_fields: + field: + script: + source: "field('boolean_no_doc_values').empty" + - match: { hits.hits.0.fields.field.0: true } + - do: search: index: test @@ -2302,6 +2385,17 @@ keyword_synthetic: source: "doc['keyword'].value" - match: { hits.hits.0.fields.field.0: "not split at all" } + - do: + search: + index: test_synthetic + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('keyword').get('null')" + - match: { hits.hits.0.fields.field.0: "not split at all" } + - do: search: index: test_synthetic @@ -6124,3 +6218,38 @@ unsupported date methods: source: "/* avoid stash */ $('date', null).get(ChronoField.YEAR_OF_ERA)" - match: { hits.hits.0.fields.field.0: 2017 } +--- +_id_field: + - do: + catch: bad_request + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "doc['_id'].value" + - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" } + + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('_id').empty" + - match: { hits.hits.0.fields.field.0: true } + + - do: + search: + index: test + body: + query: { term: { _id: "1" } } + script_fields: + field: + script: + source: "field('_id').get(0)" + - match: { hits.hits.0.fields.field.0: 0 } diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java index ad49b305c8ef7..e78ac93170d61 100644 --- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java +++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java @@ -318,6 +318,11 @@ public Query phrasePrefixQuery(TokenStream stream, int slop, int maxExpansions, return toQuery(query, queryShardContext); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return fieldDataContext.fielddataOperation() == FielddataOperation.SCRIPT; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { if (fieldDataContext.fielddataOperation() != FielddataOperation.SCRIPT) { 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 43951878933fa..147a95552cf74 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 @@ -303,6 +303,14 @@ public Query rangeQuery( return NumberFieldMapper.NumberType.LONG.rangeQuery(name(), lo, hi, true, true, hasDocValues(), context, isIndexed()); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentIdFieldMapper.java b/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentIdFieldMapper.java index 7e9b6916e99d4..0958ba7d8ae15 100644 --- a/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentIdFieldMapper.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentIdFieldMapper.java @@ -57,6 +57,11 @@ public boolean eagerGlobalOrdinals() { return eagerGlobalOrdinals; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentJoinFieldMapper.java b/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentJoinFieldMapper.java index 2bbd5e81444b7..0e022e97bd6ac 100644 --- a/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentJoinFieldMapper.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentJoinFieldMapper.java @@ -152,6 +152,11 @@ public String typeName() { return CONTENT_TYPE; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new SortedSetOrdinalsIndexFieldData.Builder( diff --git a/plugins/analysis-icu/src/main/java/org/elasticsearch/plugin/analysis/icu/ICUCollationKeywordFieldMapper.java b/plugins/analysis-icu/src/main/java/org/elasticsearch/plugin/analysis/icu/ICUCollationKeywordFieldMapper.java index 19f1d0455630d..24c3a47fef545 100644 --- a/plugins/analysis-icu/src/main/java/org/elasticsearch/plugin/analysis/icu/ICUCollationKeywordFieldMapper.java +++ b/plugins/analysis-icu/src/main/java/org/elasticsearch/plugin/analysis/icu/ICUCollationKeywordFieldMapper.java @@ -106,6 +106,11 @@ protected String parseSourceValue(Object value) { }; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java b/plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java index 706fb057cc8ee..db4276884097d 100644 --- a/plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java +++ b/plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java @@ -88,6 +88,11 @@ public String typeName() { return CONTENT_TYPE; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/IndexService.java b/server/src/main/java/org/elasticsearch/index/IndexService.java index 05c6fd63c3fcb..ebd898a8e4be6 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexService.java +++ b/server/src/main/java/org/elasticsearch/index/IndexService.java @@ -47,6 +47,7 @@ import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.EngineFactory; import org.elasticsearch.index.fielddata.FieldDataContext; +import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.fielddata.IndexFieldDataService; import org.elasticsearch.index.fielddata.ordinals.GlobalOrdinalsAccounting; @@ -660,7 +661,17 @@ public SearchExecutionContext newSearchExecutionContext( shardRequestIndex, indexSettings, indexCache.bitsetFilterCache(), - indexFieldData::getForField, + new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return indexFieldData.isFielddataSupportedForField(fieldType, fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return indexFieldData.getForField(fieldType, fieldDataContext); + } + }, mapperService(), mapperService().mappingLookup(), similarityService(), diff --git a/server/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java b/server/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java index e4030a0de9d61..d98d1f95ef941 100644 --- a/server/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java +++ b/server/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java @@ -85,6 +85,13 @@ public synchronized void clearField(final String fieldName) { ExceptionsHelper.maybeThrowRuntimeAndSuppress(exceptions); } + /** + * Returns if fielddata is available for the provided field type in the provided context. + */ + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + /** * Returns fielddata for the provided field type, given the provided fully qualified index name, while also making * a {@link SearchLookup} supplier available that is required for runtime fields. diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java index 98aaf3fbda596..5daf49cbbd695 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java @@ -119,6 +119,11 @@ public BytesReference valueForDisplay(Object value) { return bytes; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java index f2383148c31ed..79a02c540a829 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java @@ -254,6 +254,14 @@ public Boolean valueForDisplay(Object value) { }; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptFieldType.java index ce1dc432a8372..64219131f1bbe 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptFieldType.java @@ -108,6 +108,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) { return DocValueFormat.BOOLEAN; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public BooleanScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new BooleanScriptFieldData.Builder(name(), leafFactory(fieldDataContext.lookupSupplier().get()), BooleanDocValuesField::new); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index f57b3229b8062..669469058fa29 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -771,6 +771,14 @@ public Function pointReaderIfPossible() { return null; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/DateScriptFieldType.java index 95bf70f49d7c8..fa605e3b598dc 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DateScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DateScriptFieldType.java @@ -177,6 +177,11 @@ public DocValueFormat docValueFormat(@Nullable String format, ZoneId timeZone) { return new DocValueFormat.DateTime(dateTimeFormatter, timeZone, Resolution.MILLISECONDS); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public DateScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new DateScriptFieldData.Builder( diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java index d98bb8b367694..a67aab0359451 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java @@ -163,6 +163,9 @@ private static void executeIndexTimeScripts(DocumentParserContext context) { (ft, lookup, fto) -> ft.fielddataBuilder( new FieldDataContext(context.indexSettings().getIndex().getName(), lookup, context.mappingLookup()::sourcePaths, fto) ).build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()), + (ft, lookup, fto) -> ft.isFielddataSupported( + new FieldDataContext(context.indexSettings().getIndex().getName(), lookup, context.mappingLookup()::sourcePaths, fto) + ), (ctx, doc) -> Source.fromBytes(context.sourceToParse().source()) ); // field scripts can be called both by the loop at the end of this method and via diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptFieldType.java index 6adf7a8044500..2d4e95f2479bd 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptFieldType.java @@ -103,6 +103,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) { return new DocValueFormat.Decimal(format); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public DoubleScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new DoubleScriptFieldData.Builder(name(), leafFactory(fieldDataContext.lookupSupplier().get()), DoubleDocValuesField::new); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java index 4f96723235035..74d06eb5ab83f 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java @@ -446,6 +446,14 @@ private boolean isPointGeometry(LatLonGeometry[] geometries) { return geometries.length == 1 && geometries[0] instanceof org.apache.lucene.geo.Point; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointScriptFieldType.java index 28789ed149200..c4be530bcadf7 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointScriptFieldType.java @@ -109,6 +109,11 @@ public Query termQuery(Object value, SearchExecutionContext context) { ); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public GeoPointScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new GeoPointScriptFieldData.Builder( diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java index c24b3077f700c..032e0f5795160 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java @@ -64,6 +64,11 @@ public Query existsQuery(SearchExecutionContext context) { return new MatchAllDocsQuery(); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new ConstantIndexFieldData.Builder( diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java index 49339c756bc7f..c5becc835eafb 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java @@ -404,6 +404,11 @@ public static Query rangeQuery( return builder.apply(lower, upper); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IpScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/IpScriptFieldType.java index e8f04ae062f49..b95ca8c396870 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IpScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IpScriptFieldType.java @@ -102,6 +102,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) { return DocValueFormat.IP; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IpScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new IpScriptFieldData.Builder(name(), leafFactory(fieldDataContext.lookupSupplier().get()), IpDocValuesField::new); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index 8d9c77f503ab9..1a5ee37f9b71d 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -575,6 +575,20 @@ NamedAnalyzer normalizer() { return normalizer; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + if (hasDocValues()) { + return true; + } + if (isSyntheticSource && isStored() == false) { + return false; + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptFieldType.java index b09076083f872..6ad11375dee88 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptFieldType.java @@ -108,6 +108,11 @@ public Object valueForDisplay(Object value) { return binaryValue.utf8ToString(); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public StringScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new StringScriptFieldData.Builder(name(), leafFactory(fieldDataContext.lookupSupplier().get()), KeywordDocValuesField::new); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/LongScriptFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/LongScriptFieldType.java index ca1147c6796de..4f796d35f0936 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/LongScriptFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/LongScriptFieldType.java @@ -103,6 +103,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) { return new DocValueFormat.Decimal(format); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public LongScriptFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new LongScriptFieldData.Builder(name(), leafFactory(fieldDataContext.lookupSupplier().get()), LongDocValuesField::new); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java index d7fa0dae21b38..73dea380d91c9 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java @@ -103,6 +103,15 @@ public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext throw new IllegalArgumentException("Fielddata is not supported on field [" + name() + "] of type [" + typeName() + "]"); } + /** + * Return if fielddata is supported for this field in the given context + * + * @param fieldDataContext the context for the fielddata + */ + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return false; + } + /** * Create a helper class to fetch field values during the {@link FetchFieldsPhase}. * diff --git a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java index 34763eda69a28..42243d7f6dcaf 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java @@ -1578,6 +1578,14 @@ public Function pointReaderIfPossible() { return null; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java index e2821189f0564..58c993a1e87eb 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java @@ -117,6 +117,11 @@ public Query termsQuery(Collection values, SearchExecutionContext context) { return new TermInSetQuery(name(), bytesRefs); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return fieldDataEnabled.getAsBoolean(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { if (fieldDataEnabled.getAsBoolean() == false) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index fcd2a425a6625..063eb405f5e9b 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -218,6 +218,11 @@ public RangeType rangeType() { return rangeType; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java index 8e8c58b35c68a..86ce532feaab0 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java @@ -237,6 +237,11 @@ public Query rangeQuery( return LongPoint.newRangeQuery(name(), l, u); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java index 4c3e1d38b6d57..6a24308f20978 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java @@ -926,6 +926,14 @@ public boolean isAggregatable() { return fielddata; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return fielddata; + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/TimeSeriesIdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/TimeSeriesIdFieldMapper.java index a85ba6d0e9a45..77f20536e0200 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/TimeSeriesIdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/TimeSeriesIdFieldMapper.java @@ -116,6 +116,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) { return DocValueFormat.TIME_SERIES_ID; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/VersionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/VersionFieldMapper.java index 0de2a27fbaac2..2c19a6c1f802d 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/VersionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/VersionFieldMapper.java @@ -54,6 +54,11 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format) return new DocValueFetcher(docValueFormat(format, null), context.getForField(this, FielddataOperation.SEARCH)); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/flattened/FlattenedFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/flattened/FlattenedFieldMapper.java index 51be6290df657..91b516949f57b 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/flattened/FlattenedFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/flattened/FlattenedFieldMapper.java @@ -408,6 +408,11 @@ public BytesRef indexedValueForSearch(Object value) { return new BytesRef(keyedValue); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); @@ -709,6 +714,11 @@ public Object valueForDisplay(Object value) { return binaryValue.utf8ToString(); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java index bd9b9df68aff2..fa17328b3e63b 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java @@ -825,6 +825,11 @@ public boolean isAggregatable() { return false; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return elementType.fielddataBuilder(this, fieldDataContext); diff --git a/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java b/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java index 6f0c589d3f25b..604775161a231 100644 --- a/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java +++ b/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java @@ -66,7 +66,6 @@ import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; -import java.util.function.BiFunction; import java.util.function.BooleanSupplier; import java.util.function.Function; import java.util.function.LongSupplier; @@ -85,7 +84,7 @@ public class SearchExecutionContext extends QueryRewriteContext { private final SimilarityService similarityService; private final BitsetFilterCache bitsetFilterCache; - private final BiFunction> indexFieldDataLookup; + private final IndexFieldDataLookup indexFieldDataLookup; private SearchLookup lookup; private final int shardId; @@ -98,6 +97,12 @@ public class SearchExecutionContext extends QueryRewriteContext { private final Map namedQueries = new HashMap<>(); private NestedScope nestedScope; + public interface IndexFieldDataLookup { + boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext); + + IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext); + } + /** * Build a {@linkplain SearchExecutionContext}. */ @@ -106,7 +111,7 @@ public SearchExecutionContext( int shardRequestIndex, IndexSettings indexSettings, BitsetFilterCache bitsetFilterCache, - BiFunction> indexFieldDataLookup, + IndexFieldDataLookup indexFieldDataLookup, MapperService mapperService, MappingLookup mappingLookup, SimilarityService similarityService, @@ -179,7 +184,7 @@ private SearchExecutionContext( int shardRequestIndex, IndexSettings indexSettings, BitsetFilterCache bitsetFilterCache, - BiFunction> indexFieldDataLookup, + IndexFieldDataLookup indexFieldDataLookup, MapperService mapperService, MappingLookup mappingLookup, SimilarityService similarityService, @@ -264,7 +269,7 @@ public BitSetProducer bitsetFilter(Query filter) { @SuppressWarnings("unchecked") public > IFD getForField(MappedFieldType fieldType, FielddataOperation fielddataOperation) { - return (IFD) indexFieldDataLookup.apply( + return (IFD) indexFieldDataLookup.getForField( fieldType, new FieldDataContext( getFullyQualifiedIndex().getName(), @@ -418,7 +423,11 @@ public void setLookupProviders( // TODO can we assert that this is only called during FetchPhase? this.lookup = new SearchLookup( this::getFieldType, - (fieldType, searchLookup, fielddataOperation) -> indexFieldDataLookup.apply( + (fieldType, searchLookup, fielddataOperation) -> indexFieldDataLookup.getForField( + fieldType, + new FieldDataContext(getFullyQualifiedIndex().getName(), searchLookup, this::sourcePath, fielddataOperation) + ), + (fieldType, searchLookup, fielddataOperation) -> indexFieldDataLookup.isFielddataSupportedForField( fieldType, new FieldDataContext(getFullyQualifiedIndex().getName(), searchLookup, this::sourcePath, fielddataOperation) ), diff --git a/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java b/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java index bd6971dceb7be..51e517256b31e 100644 --- a/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java +++ b/server/src/main/java/org/elasticsearch/search/lookup/LeafDocLookup.java @@ -15,6 +15,7 @@ import org.elasticsearch.index.fielddata.SourceValueFetcherIndexFieldData; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.script.field.DocValuesScriptFieldFactory; +import org.elasticsearch.script.field.EmptyField; import org.elasticsearch.script.field.Field; import java.io.IOException; @@ -33,6 +34,7 @@ public class LeafDocLookup implements Map> { private final Function fieldTypeLookup; private final BiFunction> fieldDataLookup; + private final BiFunction fieldDataPredicate; private final LeafReaderContext reader; /* @@ -81,10 +83,12 @@ script that uses both types of access (likely common during upgrades) LeafDocLookup( Function fieldTypeLookup, BiFunction> fieldDataLookup, + BiFunction fieldDataPredicate, LeafReaderContext reader ) { this.fieldTypeLookup = fieldTypeLookup; this.fieldDataLookup = fieldDataLookup; + this.fieldDataPredicate = fieldDataPredicate; this.reader = reader; } @@ -100,6 +104,23 @@ private FieldFactoryWrapper getFactoryForField(String fieldName) { throw new IllegalArgumentException("No field found for [" + fieldName + "] in mapping"); } + if (fieldDataPredicate.apply(fieldType, SCRIPT) == false) { + return new FieldFactoryWrapper(new DocValuesScriptFieldFactory() { + @Override + public void setNextDocId(int docId) {} + + @Override + public ScriptDocValues toScriptDocValues() { + throw new UnsupportedOperationException("field-style api accessor"); + } + + @Override + public Field toScriptField() { + return new EmptyField(fieldName); + } + }); + } + // Load the field data on behalf of the script. Otherwise, it would require // additional permissions to deal with pagedbytes/ramusagestimator/etc. return AccessController.doPrivileged(new PrivilegedAction() { diff --git a/server/src/main/java/org/elasticsearch/search/lookup/SearchLookup.java b/server/src/main/java/org/elasticsearch/search/lookup/SearchLookup.java index 06f71fbf2514d..cdb69919c959f 100644 --- a/server/src/main/java/org/elasticsearch/search/lookup/SearchLookup.java +++ b/server/src/main/java/org/elasticsearch/search/lookup/SearchLookup.java @@ -50,32 +50,38 @@ public class SearchLookup implements SourceProvider { Supplier, MappedFieldType.FielddataOperation, IndexFieldData> fieldDataLookup; + private final TriFunction, MappedFieldType.FielddataOperation, Boolean> fieldDataPredicate; + private final Function fieldLookupProvider; /** * Create a new SearchLookup, using the default stored fields provider - * @param fieldTypeLookup defines how to look up field types - * @param fieldDataLookup defines how to look up field data - * @param sourceProvider defines how to look up the source + * @param fieldTypeLookup defines how to look up field types + * @param fieldDataLookup defines how to look up field data + * @param fieldDataPredicate defines if it is possible to access field data + * @param sourceProvider defines how to look up the source */ public SearchLookup( Function fieldTypeLookup, TriFunction, MappedFieldType.FielddataOperation, IndexFieldData> fieldDataLookup, + TriFunction, MappedFieldType.FielddataOperation, Boolean> fieldDataPredicate, SourceProvider sourceProvider ) { - this(fieldTypeLookup, fieldDataLookup, sourceProvider, LeafFieldLookupProvider.fromStoredFields()); + this(fieldTypeLookup, fieldDataLookup, fieldDataPredicate, sourceProvider, LeafFieldLookupProvider.fromStoredFields()); } /** * Create a new SearchLookup, using the default stored fields provider * @param fieldTypeLookup defines how to look up field types * @param fieldDataLookup defines how to look up field data + * @param fieldDataPredicate defines if it is possible to access field data * @param sourceProvider defines how to look up the source * @param fieldLookupProvider defines how to look up stored fields */ public SearchLookup( Function fieldTypeLookup, TriFunction, MappedFieldType.FielddataOperation, IndexFieldData> fieldDataLookup, + TriFunction, MappedFieldType.FielddataOperation, Boolean> fieldDataPredicate, SourceProvider sourceProvider, Function fieldLookupProvider ) { @@ -83,6 +89,7 @@ public SearchLookup( this.fieldChain = Collections.emptySet(); this.sourceProvider = sourceProvider; this.fieldDataLookup = fieldDataLookup; + this.fieldDataPredicate = fieldDataPredicate; this.fieldLookupProvider = fieldLookupProvider; } @@ -98,6 +105,7 @@ private SearchLookup(SearchLookup searchLookup, Set fieldChain) { this.sourceProvider = searchLookup.sourceProvider; this.fieldTypeLookup = searchLookup.fieldTypeLookup; this.fieldDataLookup = searchLookup.fieldDataLookup; + this.fieldDataPredicate = searchLookup.fieldDataPredicate; this.fieldLookupProvider = searchLookup.fieldLookupProvider; } @@ -125,7 +133,7 @@ public final SearchLookup forkAndTrackFieldReferences(String field) { public LeafSearchLookup getLeafSearchLookup(LeafReaderContext context) { return new LeafSearchLookup( context, - new LeafDocLookup(fieldTypeLookup, this::getForField, context), + new LeafDocLookup(fieldTypeLookup, this::getForField, this::isFielddataSupportedForField, context), sourceProvider, new LeafStoredFieldsLookup(fieldTypeLookup, fieldLookupProvider.apply(context)) ); @@ -135,6 +143,10 @@ public MappedFieldType fieldType(String fieldName) { return fieldTypeLookup.apply(fieldName); } + private boolean isFielddataSupportedForField(MappedFieldType fieldType, MappedFieldType.FielddataOperation options) { + return fieldDataPredicate.apply(fieldType, () -> forkAndTrackFieldReferences(fieldType.name()), options); + } + public IndexFieldData getForField(MappedFieldType fieldType, MappedFieldType.FielddataOperation options) { return fieldDataLookup.apply(fieldType, () -> forkAndTrackFieldReferences(fieldType.name()), options); } diff --git a/server/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java b/server/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java index 046facfe690c2..8159d862a9872 100644 --- a/server/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java +++ b/server/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java @@ -141,7 +141,7 @@ public void testGetForFieldRuntimeField() { searchLookupSetOnce.set(fdc.lookupSupplier()); return (IndexFieldData.Builder) (cache, breakerService) -> null; }); - SearchLookup searchLookup = new SearchLookup(null, null, (ctx, doc) -> null); + SearchLookup searchLookup = new SearchLookup(null, null, null, (ctx, doc) -> null); ifdService.getForField(ft, new FieldDataContext("qualified", () -> searchLookup, null, MappedFieldType.FielddataOperation.SEARCH)); assertSame(searchLookup, searchLookupSetOnce.get().get()); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java b/server/src/test/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java index 41bbb2f7adc0a..8d860e24ce3bb 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java @@ -275,6 +275,7 @@ protected static SearchExecutionContext mockContext( context::getFieldType, (mft, lookupSupplier, fdo) -> mft.fielddataBuilder(new FieldDataContext("test", lookupSupplier, context::sourcePath, fdo)) .build(null, null), + (mft, lookupSupplier, fdo) -> mft.isFielddataSupported(new FieldDataContext("test", lookupSupplier, context::sourcePath, fdo)), sourceProvider ); when(context.lookup()).thenReturn(lookup); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldScriptTests.java index d628990aecb78..2a39494a5c74f 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldScriptTests.java @@ -58,7 +58,7 @@ public void testTooManyValues() throws IOException { BooleanFieldScript script = new BooleanFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompositeRuntimeFieldTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompositeRuntimeFieldTests.java index 162b45cef971c..222027a69bb9d 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompositeRuntimeFieldTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompositeRuntimeFieldTests.java @@ -345,6 +345,9 @@ public void testParseDocumentSubFieldAccess() throws IOException { (mft, lookupSupplier, fdo) -> mft.fielddataBuilder( new FieldDataContext("test", lookupSupplier, mapperService.mappingLookup()::sourcePaths, fdo) ).build(null, null), + (mft, lookupSupplier, fdo) -> mft.isFielddataSupported( + new FieldDataContext("test", lookupSupplier, mapperService.mappingLookup()::sourcePaths, fdo) + ), SourceProvider.fromStoredFields() ); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldScriptTests.java index 685dc52eb0635..4c0de4f9071e9 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldScriptTests.java @@ -68,7 +68,7 @@ public void testTooManyValues() throws IOException { DateFieldScript script = new DateFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random())), OnScriptError.FAIL, reader.leaves().get(0) @@ -105,7 +105,7 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException { DateFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), DateFormatter.forPattern("epoch_millis"), OnScriptError.FAIL ); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldScriptTests.java index b9d86e3a1629f..597a72574aa82 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldScriptTests.java @@ -66,7 +66,7 @@ public void testTooManyValues() throws IOException { DoubleFieldScript script = new DoubleFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -102,7 +102,7 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException { DoubleFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), OnScriptError.FAIL ); DoubleFieldScript doubleFieldScript = leafFactory.newInstance(reader.leaves().get(0)); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldScriptTests.java index 8d15d754a39cc..0bbfa4106f07e 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldScriptTests.java @@ -60,7 +60,7 @@ public void testTooManyValues() throws IOException { GeoPointFieldScript script = new GeoPointFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredFieldMapperTests.java index 7eff2dc73d76f..22b51b9d8d8f0 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredFieldMapperTests.java @@ -64,7 +64,12 @@ public void testFetchIgnoredFieldValue() throws IOException { withLuceneIndex(mapperService, iw -> { iw.addDocument(mapperService.documentMapper().parse(source(b -> b.field("field", "value"))).rootDoc()); }, iw -> { - SearchLookup lookup = new SearchLookup(mapperService::fieldType, fieldDataLookup(mapperService), (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup( + mapperService::fieldType, + fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), + (ctx, doc) -> null + ); SearchExecutionContext searchExecutionContext = mock(SearchExecutionContext.class); when(searchExecutionContext.lookup()).thenReturn(lookup); IgnoredFieldMapper.IgnoredFieldType ft = (IgnoredFieldMapper.IgnoredFieldType) mapperService.fieldType("_ignored"); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IndexFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IndexFieldMapperTests.java index d461fac38049e..8a24e12d0be57 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/IndexFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/IndexFieldMapperTests.java @@ -59,7 +59,12 @@ public void testFetchFieldValue() throws IOException { iw.addDocument(mapperService.documentMapper().parse(source).rootDoc()); }, iw -> { IndexFieldMapper.IndexFieldType ft = (IndexFieldMapper.IndexFieldType) mapperService.fieldType("_index"); - SearchLookup lookup = new SearchLookup(mapperService::fieldType, fieldDataLookup(mapperService), (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup( + mapperService::fieldType, + fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), + (ctx, doc) -> null + ); SearchExecutionContext searchExecutionContext = createSearchExecutionContext(mapperService); ValueFetcher valueFetcher = ft.valueFetcher(searchExecutionContext, null); IndexSearcher searcher = newSearcher(iw); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IpFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IpFieldScriptTests.java index 5db04a76d4170..a4dcf25b2cfd8 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/IpFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/IpFieldScriptTests.java @@ -67,7 +67,7 @@ public void testTooManyValues() throws IOException { IpFieldScript script = new IpFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -103,7 +103,7 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException { IpFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), OnScriptError.FAIL ); IpFieldScript ipFieldScript = leafFactory.newInstance(reader.leaves().get(0)); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/LongFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/LongFieldScriptTests.java index 756d0699826af..14e3987c9248f 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/LongFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/LongFieldScriptTests.java @@ -66,7 +66,7 @@ public void testTooManyValues() throws IOException { LongFieldScript script = new LongFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -102,7 +102,7 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException { LongFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), OnScriptError.FAIL ); LongFieldScript longFieldScript = leafFactory.newInstance(reader.leaves().get(0)); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java index 86a4d5777b2e4..524c685724b91 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java @@ -66,6 +66,7 @@ public void testFetchValue() throws Exception { SearchLookup lookup = new SearchLookup( mapperService::fieldType, fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), SourceProvider.fromStoredFields() ); SearchExecutionContext searchExecutionContext = createSearchExecutionContext(mapperService); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java index c4f2b4db1e7ae..6dcb0bba0ea06 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java @@ -76,6 +76,7 @@ public void testFetchIdFieldValue() throws IOException { SearchLookup lookup = new SearchLookup( mapperService::fieldType, fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), SourceProvider.fromStoredFields() ); SearchExecutionContext searchExecutionContext = mock(SearchExecutionContext.class); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RoutingFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RoutingFieldMapperTests.java index 1e1dc79e4c7f9..476903f38dc47 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RoutingFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RoutingFieldMapperTests.java @@ -75,7 +75,12 @@ public void testFetchRoutingFieldValue() throws IOException { mapperService, iw -> { iw.addDocument(mapperService.documentMapper().parse(source("1", b -> {}, "abcd")).rootDoc()); }, iw -> { - SearchLookup lookup = new SearchLookup(mapperService::fieldType, fieldDataLookup(mapperService), (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup( + mapperService::fieldType, + fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), + (ctx, doc) -> null + ); SearchExecutionContext searchExecutionContext = mock(SearchExecutionContext.class); when(searchExecutionContext.lookup()).thenReturn(lookup); RoutingFieldMapper.RoutingFieldType ft = (RoutingFieldMapper.RoutingFieldType) mapperService.fieldType("_routing"); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/StringFieldScriptTests.java b/server/src/test/java/org/elasticsearch/index/mapper/StringFieldScriptTests.java index 40c7193671593..ae398e4253236 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/StringFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/StringFieldScriptTests.java @@ -65,7 +65,7 @@ public void testTooManyValues() throws IOException { StringFieldScript script = new StringFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -92,7 +92,7 @@ public void testTooManyChars() throws IOException { StringFieldScript script = new StringFieldScript( "test", Map.of(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, fdt) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -133,7 +133,7 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException { StringFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), OnScriptError.FAIL ); StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0)); @@ -163,7 +163,7 @@ public final void testFromSourceDoesNotEnforceCharsLimit() throws IOException { StringFieldScript.LeafFactory leafFactory = fromSource().newFactory( "field", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()), + new SearchLookup(field -> null, (ft, l, fdt) -> null, (ft, l, ftd) -> false, SourceProvider.fromStoredFields()), OnScriptError.FAIL ); StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0)); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/VersionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/VersionFieldMapperTests.java index a890c1286e43a..5adb6aeb009ae 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/VersionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/VersionFieldMapperTests.java @@ -65,7 +65,12 @@ public void testFetchFieldValue() throws IOException { iw.addDocument(parsedDoc.rootDoc()); }, iw -> { VersionFieldMapper.VersionFieldType ft = (VersionFieldMapper.VersionFieldType) mapperService.fieldType("_version"); - SearchLookup lookup = new SearchLookup(mapperService::fieldType, fieldDataLookup(mapperService), (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup( + mapperService::fieldType, + fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), + (ctx, doc) -> null + ); SearchExecutionContext searchExecutionContext = createSearchExecutionContext(mapperService); ValueFetcher valueFetcher = ft.valueFetcher(searchExecutionContext, null); IndexSearcher searcher = newSearcher(iw); diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index 5cf329b76bb3f..d076c8c925226 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -428,12 +428,17 @@ private static SearchExecutionContext createSearchExecutionContext( IndexSettings indexSettings = new IndexSettings(indexMetadata, Settings.EMPTY); MapperService mapperService = createMapperService(indexSettings, mappingLookup); final long nowInMillis = randomNonNegativeLong(); - return new SearchExecutionContext( - 0, - 0, - indexSettings, - null, - (mappedFieldType, fdc) -> mappedFieldType.fielddataBuilder(fdc).build(null, null), + return new SearchExecutionContext(0, 0, indexSettings, null, new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.fielddataBuilder(fieldDataContext).build(null, null); + } + }, mapperService, mappingLookup, null, diff --git a/server/src/test/java/org/elasticsearch/script/CompositeFieldScriptTests.java b/server/src/test/java/org/elasticsearch/script/CompositeFieldScriptTests.java index 0a80f4310b897..2108c7b4b364c 100644 --- a/server/src/test/java/org/elasticsearch/script/CompositeFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/script/CompositeFieldScriptTests.java @@ -32,7 +32,7 @@ public void testTooManyValues() throws IOException { CompositeFieldScript script = new CompositeFieldScript( "composite", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -64,7 +64,7 @@ public void testTooManyChars() throws IOException { CompositeFieldScript script = new CompositeFieldScript( "composite", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { @@ -78,7 +78,7 @@ public void execute() { StringFieldScript stringFieldScript = new StringFieldScript( "composite.leaf", Collections.emptyMap(), - new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), OnScriptError.FAIL, reader.leaves().get(0) ) { diff --git a/server/src/test/java/org/elasticsearch/script/field/SortedNumericDocValuesLongFieldScriptTests.java b/server/src/test/java/org/elasticsearch/script/field/SortedNumericDocValuesLongFieldScriptTests.java index c63e43122918e..d387c4e986412 100644 --- a/server/src/test/java/org/elasticsearch/script/field/SortedNumericDocValuesLongFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/script/field/SortedNumericDocValuesLongFieldScriptTests.java @@ -39,7 +39,7 @@ public void testValuesLimitIsNotEnforced() throws IOException { try (DirectoryReader reader = iw.getReader()) { SortedNumericDocValuesLongFieldScript docValues = new SortedNumericDocValuesLongFieldScript( "test", - new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), reader.leaves().get(0) ); List values = new ArrayList<>(); diff --git a/server/src/test/java/org/elasticsearch/script/field/SortedSetDocValuesStringFieldScriptTests.java b/server/src/test/java/org/elasticsearch/script/field/SortedSetDocValuesStringFieldScriptTests.java index 3bbea2b3c6b73..7f0e741f35b28 100644 --- a/server/src/test/java/org/elasticsearch/script/field/SortedSetDocValuesStringFieldScriptTests.java +++ b/server/src/test/java/org/elasticsearch/script/field/SortedSetDocValuesStringFieldScriptTests.java @@ -40,7 +40,7 @@ public void testValuesLimitIsNotEnforced() throws IOException { try (DirectoryReader reader = iw.getReader()) { SortedSetDocValuesStringFieldScript docValues = new SortedSetDocValuesStringFieldScript( "test", - new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ctx, doc) -> null), + new SearchLookup(field -> null, (ft, lookup, ftd) -> null, (ft, lookup, ftd) -> false, (ctx, doc) -> null), reader.leaves().get(0) ); List values = new ArrayList<>(); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/range/RangeAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/range/RangeAggregatorTests.java index 148be0aec58e7..dba8ef47debb1 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/range/RangeAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/range/RangeAggregatorTests.java @@ -595,7 +595,7 @@ public void testOverlappingRanges() throws IOException { */ public void testRuntimeFieldTopLevelQueryNotOptimized() throws IOException { long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4; - SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, (ft, l, ftd) -> false, (ctx, doc) -> null); StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, OnScriptError.FAIL, ctx) { @Override public void execute() { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java index 12d323fb15ca0..4adfd8bb0c546 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java @@ -1964,7 +1964,7 @@ public void testWithFilterAndPreciseSize() throws IOException { */ public void testRuntimeFieldTopLevelNotOptimized() throws IOException { long totalDocs = 500; - SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, (ctx, doc) -> null); + SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, (ft, l, ftd) -> false, (ctx, doc) -> null); StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, OnScriptError.FAIL, ctx) { @Override public void execute() { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/support/ScriptValuesTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/support/ScriptValuesTests.java index ff6b4ffcdc28f..d3a31a1daf89e 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/support/ScriptValuesTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/support/ScriptValuesTests.java @@ -36,7 +36,7 @@ private static class FakeAggregationScript extends AggregationScript { int index; FakeAggregationScript(Object[][] values) { - super(Collections.emptyMap(), new SearchLookup(null, null, (ctx, doc) -> null) { + super(Collections.emptyMap(), new SearchLookup(null, null, null, (ctx, doc) -> null) { @Override public LeafSearchLookup getLeafSearchLookup(LeafReaderContext context) { diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/FieldFetcherTests.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/FieldFetcherTests.java index acd69788737d2..2150107213698 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/FieldFetcherTests.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/FieldFetcherTests.java @@ -48,7 +48,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.BiFunction; import static java.util.Collections.emptyMap; import static org.elasticsearch.xcontent.ObjectPath.eval; @@ -241,10 +240,17 @@ public void testMetadataFields() throws IOException { new FieldAndFormat("_ignored", null) ); FieldFetcher fieldFetcher = FieldFetcher.create( - newSearchExecutionContext( - mapperService, - (ft, fdc) -> fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()) - ), + newSearchExecutionContext(mapperService, new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataPredicate(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + + @Override + public IndexFieldData getForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + }), fieldList ); IndexSearcher searcher = newSearcher(iw); @@ -1360,7 +1366,17 @@ public void testFetchRuntimeFieldWithSourceDisabled() throws IOException { MapperService mapperService = createMapperService(mapping); SearchExecutionContext searchExecutionContext = newSearchExecutionContext( mapperService, - (ft, fdc) -> fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()) + new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataPredicate(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + + @Override + public IndexFieldData getForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + } ); withLuceneIndex(mapperService, iw -> iw.addDocument(new LuceneDocument()), iw -> { FieldFetcher fieldFetcher = FieldFetcher.create(searchExecutionContext, fieldAndFormatList("runtime_field", null, false)); @@ -1390,7 +1406,17 @@ public void testFetchMetadataFieldWithSourceDisabled() throws IOException { MapperService mapperService = createMapperService(mapping); SearchExecutionContext searchExecutionContext = newSearchExecutionContext( mapperService, - (ft, fdc) -> fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()) + new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataPredicate(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + + @Override + public IndexFieldData getForField(MappedFieldType ft, FieldDataContext fdc) { + return fieldDataLookup(fdc.sourcePathsLookup()).apply(ft, fdc.lookupSupplier(), fdc.fielddataOperation()); + } + } ); withLuceneIndex(mapperService, iw -> { ParsedDocument parsedDocument = mapperService.documentMapper().parse(source("{}")); @@ -1485,7 +1511,7 @@ private static SearchExecutionContext newSearchExecutionContext(MapperService ma private static SearchExecutionContext newSearchExecutionContext( MapperService mapperService, - BiFunction> indexFieldDataLookup + SearchExecutionContext.IndexFieldDataLookup indexFieldDataLookup ) { Settings settings = indexSettings(IndexVersion.current(), 1, 0).put(IndexMetadata.SETTING_INDEX_UUID, "uuid").build(); IndexMetadata indexMetadata = new IndexMetadata.Builder("test").settings(settings).build(); diff --git a/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java b/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java index 40baaa68452f7..48723b54e90bf 100644 --- a/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java +++ b/server/src/test/java/org/elasticsearch/search/lookup/LeafDocLookupTests.java @@ -65,6 +65,7 @@ public void setUp() throws Exception { docLookup = new LeafDocLookup( field -> field.equals("field") ? fieldType1 : field.equals("alias") ? fieldType2 : null, (fieldType, fielddataType) -> fieldType == fieldType1 ? fieldData1 : fieldType == fieldType2 ? fieldData2 : null, + (fieldType, fielddataType) -> fieldType == fieldType1 || fieldType == fieldType2, null ); } @@ -104,7 +105,7 @@ public void testFlattenedField() throws IOException { return fieldType2; } return null; - }, fieldDataSupplier, null); + }, fieldDataSupplier, (ft, fdt) -> true, null); assertEquals(docValues1, docLookup.get("flattened.key1")); assertEquals(docValues2, docLookup.get("flattened.key2")); @@ -209,6 +210,16 @@ public void testParallelCache() { } else { throw new IllegalArgumentException("unknown mapped field type [" + mappedFieldType + "]"); } + }, (mappedFieldType, operation) -> { + if (mappedFieldType.equals(docMappedFieldType)) { + return operation == SEARCH || operation == SCRIPT; + } else if (mappedFieldType.equals(sourceMappedFieldType)) { + return operation == SCRIPT; + } else if (mappedFieldType.equals(docAndSourceMappedFieldType)) { + return operation == SEARCH || operation == SCRIPT; + } else { + return false; + } }, null); // load shared doc values field into cache w/ doc-access first diff --git a/server/src/test/java/org/elasticsearch/search/query/ScriptScoreQueryTests.java b/server/src/test/java/org/elasticsearch/search/query/ScriptScoreQueryTests.java index 6fff108cfb5ce..c9202d0006cd0 100644 --- a/server/src/test/java/org/elasticsearch/search/query/ScriptScoreQueryTests.java +++ b/server/src/test/java/org/elasticsearch/search/query/ScriptScoreQueryTests.java @@ -49,7 +49,7 @@ public class ScriptScoreQueryTests extends ESTestCase { private DirectoryReader reader; private IndexSearcher searcher; private LeafReaderContext leafReaderContext; - private final SearchLookup lookup = new SearchLookup(null, null, (ctx, doc) -> null); + private final SearchLookup lookup = new SearchLookup(null, null, null, (ctx, doc) -> null); @Before public void initSearcher() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/runtime/GeoPointScriptFieldDistanceFeatureQueryTests.java b/server/src/test/java/org/elasticsearch/search/runtime/GeoPointScriptFieldDistanceFeatureQueryTests.java index b6530e3c1c6bd..3859dcb935db2 100644 --- a/server/src/test/java/org/elasticsearch/search/runtime/GeoPointScriptFieldDistanceFeatureQueryTests.java +++ b/server/src/test/java/org/elasticsearch/search/runtime/GeoPointScriptFieldDistanceFeatureQueryTests.java @@ -84,7 +84,7 @@ public void testMatches() throws IOException { iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"location\": [-3.56, -45.98]}")))); try (DirectoryReader reader = iw.getReader()) { IndexSearcher searcher = newSearcher(reader); - SearchLookup searchLookup = new SearchLookup(null, null, SourceProvider.fromStoredFields()); + SearchLookup searchLookup = new SearchLookup(null, null, null, SourceProvider.fromStoredFields()); Function leafFactory = ctx -> new GeoPointFieldScript( "test", Map.of(), diff --git a/server/src/test/java/org/elasticsearch/search/runtime/LongScriptFieldDistanceFeatureQueryTests.java b/server/src/test/java/org/elasticsearch/search/runtime/LongScriptFieldDistanceFeatureQueryTests.java index e369abe36ded3..5ac7ac009af5d 100644 --- a/server/src/test/java/org/elasticsearch/search/runtime/LongScriptFieldDistanceFeatureQueryTests.java +++ b/server/src/test/java/org/elasticsearch/search/runtime/LongScriptFieldDistanceFeatureQueryTests.java @@ -70,7 +70,7 @@ public void testMatches() throws IOException { iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"timestamp\": [1595432181351]}")))); try (DirectoryReader reader = iw.getReader()) { IndexSearcher searcher = newSearcher(reader); - SearchLookup searchLookup = new SearchLookup(null, null, SourceProvider.fromStoredFields()); + SearchLookup searchLookup = new SearchLookup(null, null, null, SourceProvider.fromStoredFields()); Function leafFactory = ctx -> new DateFieldScript( "test", Map.of(), diff --git a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java index e0c12a594bef0..e78dd52b921fd 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java @@ -54,7 +54,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.BiFunction; import java.util.function.Function; import static java.util.Collections.emptyList; @@ -189,10 +188,19 @@ protected final SearchExecutionContext createMockSearchExecutionContext(IndexSea Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()).build() ); BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(idxSettings, mock(BitsetFilterCache.Listener.class)); - BiFunction> indexFieldDataLookup = (fieldType, fdc) -> { - IndexFieldData.Builder builder = fieldType.fielddataBuilder(fdc); - return builder.build(new IndexFieldDataCache.None(), null); + var indexFieldDataLookup = new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + IndexFieldData.Builder builder = fieldType.fielddataBuilder(fieldDataContext); + return builder.build(new IndexFieldDataCache.None(), null); + } }; + NestedLookup nestedLookup = NestedLookup.build( List.of(new NestedObjectMapper.Builder("path", IndexVersion.current()).build(MapperBuilderContext.root(false, false))) ); diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperServiceTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperServiceTestCase.java index 371ea3f35292b..1205cef6c64d2 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperServiceTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperServiceTestCase.java @@ -647,8 +647,17 @@ public void onCache(ShardId shardId, Accountable accountable) { public void onRemoval(ShardId shardId, Accountable accountable) { } - }), - (ft, fdc) -> ft.fielddataBuilder(fdc).build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()), + }), new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.fielddataBuilder(fieldDataContext).build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()); + } + }, mapperService, mapperService.mappingLookup(), similarityService, @@ -679,6 +688,18 @@ protected TriFunction, MappedFieldType.F .build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()); } + protected TriFunction, MappedFieldType.FielddataOperation, Boolean> fieldDataPredicate( + MapperService mapperService + ) { + return fieldDataPredicate(mapperService.mappingLookup()::sourcePaths); + } + + protected TriFunction, MappedFieldType.FielddataOperation, Boolean> fieldDataPredicate( + Function> sourcePathsLookup + ) { + return (mft, lookupSource, fdo) -> mft.isFielddataSupported(new FieldDataContext("test", lookupSource, sourcePathsLookup, fdo)); + } + protected final String syntheticSource(DocumentMapper mapper, CheckedConsumer build) throws IOException { try (Directory directory = newDirectory()) { RandomIndexWriter iw = new RandomIndexWriter(random(), directory); diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java index bc58a792cefc6..c1540c7b750ea 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java @@ -544,6 +544,7 @@ protected final List fetchFromDocValues(MapperService mapperService, MappedFi SearchLookup lookup = new SearchLookup( mapperService::fieldType, fieldDataLookup(mapperService), + fieldDataPredicate(mapperService), SourceProvider.fromStoredFields() ); ValueFetcher valueFetcher = new DocValueFetcher(format, lookup.getForField(ft, MappedFieldType.FielddataOperation.SEARCH)); @@ -566,7 +567,7 @@ protected final void assertScriptDocValues(MapperService mapperService, Object s SourceProvider sourceProvider = mapperService.mappingLookup().isSourceSynthetic() ? (ctx, doc) -> { throw new IllegalArgumentException("Can't load source in scripts in synthetic mode"); } : SourceProvider.fromStoredFields(); - SearchLookup searchLookup = new SearchLookup(null, null, sourceProvider); + SearchLookup searchLookup = new SearchLookup(null, null, null, sourceProvider); IndexFieldData sfd = ft.fielddataBuilder( new FieldDataContext("", () -> searchLookup, Set::of, MappedFieldType.FielddataOperation.SCRIPT) ).build(null, null); @@ -965,6 +966,7 @@ public final void testIndexTimeStoredFieldsAccess() throws IOException { SearchLookup lookup = new SearchLookup( f -> fieldType, (f, s, t) -> { throw new UnsupportedOperationException(); }, + (f, s, t) -> false, (ctx, docid) -> Source.fromBytes(doc.source()) ); diff --git a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java index ee7a8723a5a27..87c9638a820cb 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java @@ -159,7 +159,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ThreadPoolExecutor; -import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.stream.Stream; @@ -362,15 +361,26 @@ private AggregationContext createAggregationContext( .map(ft -> new FieldAliasMapper(ft.name() + "-alias", ft.name() + "-alias", ft.name())) .collect(toList()) ); - BiFunction> fieldDataBuilder = (fieldType, context) -> fieldType - .fielddataBuilder( - new FieldDataContext( - indexSettings.getIndex().getName(), - context.lookupSupplier(), - context.sourcePathsLookup(), - context.fielddataOperation() - ) - ).build(new IndexFieldDataCache.None(), breakerService); + + var indexFieldDataLookup = new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext context) { + return fieldType.fielddataBuilder( + new FieldDataContext( + indexSettings.getIndex().getName(), + context.lookupSupplier(), + context.sourcePathsLookup(), + context.fielddataOperation() + ) + ).build(new IndexFieldDataCache.None(), breakerService); + } + }; + BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(indexSettings, new BitsetFilterCache.Listener() { @Override public void onRemoval(ShardId shardId, Accountable accountable) {} @@ -383,7 +393,7 @@ public void onCache(ShardId shardId, Accountable accountable) {} -1, indexSettings, bitsetFilterCache, - fieldDataBuilder, + indexFieldDataLookup, null, mappingLookup, null, diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java index acd60c571a568..a4c12ac52da98 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java @@ -41,9 +41,12 @@ import org.elasticsearch.index.IndexVersion; import org.elasticsearch.index.analysis.IndexAnalyzers; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; +import org.elasticsearch.index.fielddata.FieldDataContext; +import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.fielddata.IndexFieldDataService; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperRegistry; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.query.CoordinatorRewriteContext; @@ -562,12 +565,17 @@ public static Predicate indexNameMatcher() { public void close() throws IOException {} SearchExecutionContext createShardContext(IndexSearcher searcher) { - return new SearchExecutionContext( - 0, - 0, - idxSettings, - bitsetFilterCache, - indexFieldDataService::getForField, + return new SearchExecutionContext(0, 0, idxSettings, bitsetFilterCache, new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return indexFieldDataService.isFielddataSupportedForField(fieldType, fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return indexFieldDataService.getForField(fieldType, fieldDataContext); + } + }, mapperService, mapperService.mappingLookup(), similarityService, diff --git a/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java b/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java index 08fad5dd3b83c..105f2541dc3f2 100644 --- a/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java +++ b/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java @@ -158,6 +158,11 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format) return SourceValueFetcher.identity(name(), context, format); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java index 21631d597f8ae..a54d24c4ac72e 100644 --- a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java +++ b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java @@ -389,6 +389,11 @@ public boolean isAggregatable() { return true; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return (cache, breakerService) -> new IndexAggregateDoubleMetricFieldData( diff --git a/x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldTypeTests.java b/x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldTypeTests.java index c32e7e583c787..e06ee9e3ce822 100644 --- a/x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldTypeTests.java +++ b/x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldTypeTests.java @@ -126,6 +126,9 @@ public void testUsedInScript() throws IOException { (mft, lookupSupplier, fdo) -> mft.fielddataBuilder( new FieldDataContext("test", lookupSupplier, searchExecutionContext::sourcePath, fdo) ).build(null, null), + (mft, lookupSupplier, fdo) -> mft.isFielddataSupported( + new FieldDataContext("test", lookupSupplier, searchExecutionContext::sourcePath, fdo) + ), (ctx, doc) -> null ); when(searchExecutionContext.lookup()).thenReturn(lookup); diff --git a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java index a530a8bf46623..4376e99bf6301 100644 --- a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java +++ b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java @@ -134,6 +134,11 @@ public String familyTypeName() { return KeywordFieldMapper.CONTENT_TYPE; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new ConstantIndexFieldData.Builder( diff --git a/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java b/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java index 4e04f85383def..44f0658f7f2ae 100644 --- a/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java +++ b/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java @@ -312,6 +312,14 @@ public Query rangeQuery( return query; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + if (fieldDataContext.fielddataOperation() == FielddataOperation.SEARCH) { + return hasDocValues(); + } + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { FielddataOperation operation = fieldDataContext.fielddataOperation(); diff --git a/x-pack/plugin/mapper-version/src/main/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapper.java b/x-pack/plugin/mapper-version/src/main/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapper.java index 9e88c516576c2..a3ad0be76f4eb 100644 --- a/x-pack/plugin/mapper-version/src/main/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapper.java +++ b/x-pack/plugin/mapper-version/src/main/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapper.java @@ -290,6 +290,11 @@ protected BytesRef indexedValueForSearch(Object value) { return encodeVersion(valueAsString).bytesRef; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return true; + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { return new SortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.KEYWORD, VersionStringDocValuesField::new); diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java index 55929a1c1b83e..85022d8bb238b 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java @@ -198,6 +198,11 @@ public GeoShapeWithDocValuesFieldType( this.geoFormatterFactory = geoFormatterFactory; } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java index 378b78111ab19..bf50766adfab8 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java @@ -200,6 +200,11 @@ public PointFieldType(String name) { this(name, true, false, true, null, Collections.emptyMap()); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java index 127a4fd1050cd..01d9726581dcd 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java @@ -151,6 +151,11 @@ public ShapeFieldType( this.queryProcessor = new ShapeQueryProcessor(); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/x-pack/plugin/wildcard/src/main/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapper.java b/x-pack/plugin/wildcard/src/main/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapper.java index e38ee029bd123..440dcc707ccc0 100644 --- a/x-pack/plugin/wildcard/src/main/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapper.java +++ b/x-pack/plugin/wildcard/src/main/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapper.java @@ -849,6 +849,11 @@ public Query termsQuery(Collection values, SearchExecutionContext context) { return new ConstantScoreQuery(bq.build()); } + @Override + public boolean isFielddataSupported(FieldDataContext fieldDataContext) { + return hasDocValues(); + } + @Override public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) { failIfNoDocValues(); diff --git a/x-pack/plugin/wildcard/src/test/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapperTests.java b/x-pack/plugin/wildcard/src/test/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapperTests.java index 79727b9279a98..0b63f1a6a8f99 100644 --- a/x-pack/plugin/wildcard/src/test/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapperTests.java +++ b/x-pack/plugin/wildcard/src/test/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapperTests.java @@ -81,7 +81,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.function.BiFunction; import static java.util.Collections.emptyMap; import static org.hamcrest.Matchers.equalTo; @@ -1081,9 +1080,17 @@ protected final SearchExecutionContext createMockContext() { Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()).build() ); BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(idxSettings, Mockito.mock(BitsetFilterCache.Listener.class)); - BiFunction> indexFieldDataLookup = (fieldType, fdc) -> { - IndexFieldData.Builder builder = fieldType.fielddataBuilder(fdc); - return builder.build(new IndexFieldDataCache.None(), null); + var indexFieldDataLookup = new SearchExecutionContext.IndexFieldDataLookup() { + @Override + public boolean isFielddataSupportedForField(MappedFieldType fieldType, FieldDataContext fieldDataContext) { + return fieldType.isFielddataSupported(fieldDataContext); + } + + @Override + public IndexFieldData getForField(MappedFieldType fieldType, FieldDataContext fdc) { + IndexFieldData.Builder builder = fieldType.fielddataBuilder(fdc); + return builder.build(new IndexFieldDataCache.None(), null); + } }; MappingLookup lookup = MappingLookup.fromMapping(Mapping.EMPTY); return new SearchExecutionContext(