Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,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.IndicesModule;
Expand All @@ -57,17 +56,13 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BooleanSupplier;
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 {

/**
Expand Down Expand Up @@ -118,8 +113,6 @@ public enum MergeReason {
private final MapperAnalyzerWrapper searchAnalyzer;
private final MapperAnalyzerWrapper searchQuoteAnalyzer;

private volatile Map<String, MappedFieldType> unmappedFieldTypes = emptyMap();

final MapperRegistry mapperRegistry;

private final BooleanSupplier idFieldDataEnabled;
Expand Down Expand Up @@ -428,30 +421,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) {
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<String, MappedFieldType> newUnmappedFieldTypes = new HashMap<>(unmappedFieldTypes);
newUnmappedFieldTypes.put(type, fieldType);
unmappedFieldTypes = unmodifiableMap(newUnmappedFieldTypes);
}
return fieldType;
}

public Analyzer indexAnalyzer() {
return this.indexAnalyzer;
}
Expand Down Expand Up @@ -544,5 +513,4 @@ public synchronized List<String> reloadSearchAnalyzers(AnalysisRegistry registry
}
return reloadedAnalyzers;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
Expand All @@ -61,6 +62,7 @@
import org.elasticsearch.transport.RemoteClusterAware;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -276,6 +278,25 @@ public Analyzer getSearchQuoteAnalyzer(MappedFieldType fieldType) {
return mapperService.searchQuoteAnalyzer();
}

/**
* 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) {
final Mapper.TypeParser.ParserContext parserContext = mapperService.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, Collections.emptyMap(), parserContext);
final Mapper.BuilderContext builderContext = new Mapper.BuilderContext(indexSettings.getSettings(), new ContentPath(1));
Mapper mapper = builder.build(builderContext);
if (mapper instanceof FieldMapper) {
return ((FieldMapper)mapper).fieldType();
}
throw new IllegalArgumentException("Mapper for type [" + type + "] must be a leaf field");
}

public IndexAnalyzers getIndexAnalyzers() {
return mapperService.getIndexAnalyzers();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.elasticsearch.index.query.QueryShardContext;
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;
Expand Down Expand Up @@ -569,7 +570,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");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,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.analysis.AnalysisModule.AnalysisProvider;
import org.elasticsearch.plugins.AnalysisPlugin;
import org.elasticsearch.plugins.Plugin;
Expand All @@ -52,7 +50,6 @@
import java.util.Map;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;

Expand Down Expand Up @@ -126,12 +123,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));
}

public void testPartitionedConstraints() {
// partitioned index must have routing
IllegalArgumentException noRoutingException = expectThrows(IllegalArgumentException.class, () -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -63,6 +68,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;

Expand Down Expand Up @@ -102,6 +108,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,
Expand Down Expand Up @@ -300,6 +312,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<String, Mapper.TypeParser> 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];
Expand Down