diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java index 2a5b9ed2bb79b..0195eb263bf83 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -50,7 +50,6 @@ import org.elasticsearch.index.analysis.ReloadableCustomAnalyzer; import org.elasticsearch.index.analysis.TokenFilterFactory; import org.elasticsearch.index.analysis.TokenizerFactory; -import org.elasticsearch.index.mapper.Mapper.BuilderContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.similarity.SimilarityService; import org.elasticsearch.indices.InvalidTypeNameException; @@ -62,7 +61,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -72,9 +70,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import static java.util.Collections.emptyMap; -import static java.util.Collections.unmodifiableMap; - public class MapperService extends AbstractIndexComponent implements Closeable { /** @@ -142,8 +137,6 @@ public enum MergeReason { private final MapperAnalyzerWrapper indexAnalyzer; - private volatile Map unmappedFieldTypes = emptyMap(); - final MapperRegistry mapperRegistry; private final BooleanSupplier idFieldDataEnabled; @@ -626,35 +619,6 @@ public ObjectMapper getObjectMapper(String name) { return this.mapper == null ? null : this.mapper.objectMappers().get(name); } - /** - * Given a type (eg. long, string, ...), return an anonymous field mapper that can be used for search operations. - */ - public MappedFieldType unmappedFieldType(String type) { - if (type.equals("string")) { - deprecationLogger.deprecate("unmapped_type_string", - "[unmapped_type:string] should be replaced with [unmapped_type:keyword]"); - type = "keyword"; - } - MappedFieldType fieldType = unmappedFieldTypes.get(type); - if (fieldType == null) { - final Mapper.TypeParser.ParserContext parserContext = documentMapperParser().parserContext(); - Mapper.TypeParser typeParser = parserContext.typeParser(type); - if (typeParser == null) { - throw new IllegalArgumentException("No mapper found for type [" + type + "]"); - } - final Mapper.Builder builder = typeParser.parse("__anonymous_" + type, emptyMap(), parserContext); - final BuilderContext builderContext = new BuilderContext(indexSettings.getSettings(), new ContentPath(1)); - fieldType = ((FieldMapper) builder.build(builderContext)).fieldType(); - - // There is no need to synchronize writes here. In the case of concurrent access, we could just - // compute some mappers several times, which is not a big deal - Map newUnmappedFieldTypes = new HashMap<>(unmappedFieldTypes); - newUnmappedFieldTypes.put(type, fieldType); - unmappedFieldTypes = unmodifiableMap(newUnmappedFieldTypes); - } - return fieldType; - } - public Analyzer indexAnalyzer() { return this.indexAnalyzer; } @@ -725,5 +689,4 @@ public synchronized List reloadSearchAnalyzers(AnalysisRegistry registry } return reloadedAnalyzers; } - } diff --git a/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java b/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java index c5cd02cf78922..0aa5e944ff8d8 100644 --- a/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.TriFunction; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.xcontent.NamedXContentRegistry; @@ -62,7 +63,6 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry; import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.transport.RemoteClusterAware; - import java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -84,6 +84,8 @@ */ public class QueryShardContext extends QueryRewriteContext { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(QueryShardContext.class); + private final ScriptService scriptService; private final IndexSettings indexSettings; private final BigArrays bigArrays; @@ -271,11 +273,20 @@ public DocumentMapper documentMapper(String type) { return mapperService.documentMapper(type); } + public Analyzer getIndexAnalyzer() { + return mapperService.indexAnalyzer(); + } + /** * Given a type (eg. long, string, ...), returns an anonymous field type that can be used for search operations. * Generally used to handle unmapped fields in the context of sorting. */ public MappedFieldType buildAnonymousFieldType(String type) { + if (type.equals("string")) { + deprecationLogger.deprecate("unmapped_type_string", + "[unmapped_type:string] should be replaced with [unmapped_type:keyword]"); + type = "keyword"; + } final Mapper.TypeParser.ParserContext parserContext = mapperService.documentMapperParser().parserContext(); Mapper.TypeParser typeParser = parserContext.typeParser(type); if (typeParser == null) { @@ -290,10 +301,6 @@ public MappedFieldType buildAnonymousFieldType(String type) { throw new IllegalArgumentException("Mapper for type [" + type + "] must be a leaf field"); } - public Analyzer getIndexAnalyzer() { - return mapperService.indexAnalyzer(); - } - public IndexAnalyzers getIndexAnalyzers() { return mapperService.getIndexAnalyzers(); } diff --git a/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java index 15fc019bedec5..db06a8fea3565 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java @@ -514,7 +514,7 @@ private MappedFieldType resolveUnmappedType(QueryShardContext context) { if (unmappedType == null) { throw new QueryShardException(context, "No mapping found for [" + fieldName + "] in order to sort on"); } - return context.getMapperService().unmappedFieldType(unmappedType); + return context.buildAnonymousFieldType(unmappedType); } private MultiValueMode localSortMode() { diff --git a/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java index 518b8403d2602..3dd995e3bf579 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java @@ -59,6 +59,7 @@ import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.MultiValueMode; +import org.elasticsearch.search.aggregations.support.CoreValuesSourceType; import java.io.IOException; import java.util.ArrayList; @@ -656,7 +657,7 @@ private IndexGeoPointFieldData fieldData(QueryShardContext context) { MappedFieldType fieldType = context.getFieldType(fieldName); if (fieldType == null) { if (ignoreUnmapped) { - fieldType = context.getMapperService().unmappedFieldType("geo_point"); + return new LatLonPointIndexFieldData(fieldName, CoreValuesSourceType.GEOPOINT); } else { throw new IllegalArgumentException("failed to find mapper for [" + fieldName + "] for geo distance based sort"); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java index a21a369904fbe..bc6d730ecff4d 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java @@ -38,9 +38,7 @@ import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.analysis.ReloadableCustomAnalyzer; import org.elasticsearch.index.analysis.TokenFilterFactory; -import org.elasticsearch.index.mapper.KeywordFieldMapper.KeywordFieldType; import org.elasticsearch.index.mapper.MapperService.MergeReason; -import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType; import org.elasticsearch.indices.InvalidTypeNameException; import org.elasticsearch.indices.analysis.AnalysisModule.AnalysisProvider; import org.elasticsearch.plugins.AnalysisPlugin; @@ -56,7 +54,6 @@ import java.util.concurrent.ExecutionException; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; @@ -192,15 +189,6 @@ public void testMappingDepthExceedsLimit() throws Throwable { assertThat(e.getMessage(), containsString("Limit of mapping depth [1] has been exceeded")); } - public void testUnmappedFieldType() { - MapperService mapperService = createIndex("index").mapperService(); - assertThat(mapperService.unmappedFieldType("keyword"), instanceOf(KeywordFieldType.class)); - assertThat(mapperService.unmappedFieldType("long"), instanceOf(NumberFieldType.class)); - // back compat - assertThat(mapperService.unmappedFieldType("string"), instanceOf(KeywordFieldType.class)); - assertWarnings("[unmapped_type:string] should be replaced with [unmapped_type:keyword]"); - } - public void testPartitionedConstraints() { // partitioned index must have routing IllegalArgumentException noRoutingException = expectThrows(IllegalArgumentException.class, () -> { diff --git a/server/src/test/java/org/elasticsearch/index/query/QueryShardContextTests.java b/server/src/test/java/org/elasticsearch/index/query/QueryShardContextTests.java index 0209f81c01b11..09db566b98077 100644 --- a/server/src/test/java/org/elasticsearch/index/query/QueryShardContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/QueryShardContextTests.java @@ -50,10 +50,15 @@ import org.elasticsearch.index.fielddata.LeafFieldData; import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.index.fielddata.plain.AbstractLeafOrdinalsFieldData; +import org.elasticsearch.index.mapper.DocumentMapperParser; import org.elasticsearch.index.mapper.IndexFieldMapper; +import org.elasticsearch.index.mapper.KeywordFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.TextFieldMapper; +import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.search.lookup.LeafDocLookup; import org.elasticsearch.search.lookup.LeafSearchLookup; import org.elasticsearch.search.lookup.SearchLookup; @@ -64,6 +69,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.function.BiFunction; import java.util.function.Supplier; @@ -103,6 +109,12 @@ public void testFailIfFieldMappingNotFound() { assertThat(result.name(), equalTo("name")); } + public void testBuildAnonymousFieldType() { + QueryShardContext context = createQueryShardContext("uuid", null); + assertThat(context.buildAnonymousFieldType("keyword"), instanceOf(KeywordFieldMapper.KeywordFieldType.class)); + assertThat(context.buildAnonymousFieldType("long"), instanceOf(NumberFieldMapper.NumberFieldType.class)); + } + public void testToQueryFails() { QueryShardContext context = createQueryShardContext(IndexMetadata.INDEX_UUID_NA_VALUE, null); Exception exc = expectThrows(Exception.class, @@ -301,6 +313,12 @@ private static QueryShardContext createQueryShardContext(String indexUuid, Strin when(mapperService.getIndexSettings()).thenReturn(indexSettings); when(mapperService.index()).thenReturn(indexMetadata.getIndex()); when(mapperService.getIndexAnalyzers()).thenReturn(indexAnalyzers); + DocumentMapperParser documentMapperParser = mock(DocumentMapperParser.class); + Map typeParserMap = IndicesModule.getMappers(Collections.emptyList()); + Mapper.TypeParser.ParserContext parserContext = new Mapper.TypeParser.ParserContext(name -> null, mapperService, + typeParserMap::get, Version.CURRENT, () -> null, null, null); + when(documentMapperParser.parserContext()).thenReturn(parserContext); + when(mapperService.documentMapperParser()).thenReturn(documentMapperParser); if (runtimeDocValues != null) { when(mapperService.fieldType(any())).thenAnswer(fieldTypeInv -> { String fieldName = (String)fieldTypeInv.getArguments()[0];