Skip to content

Commit ec65a79

Browse files
committed
Return both concrete fields and aliases in DocumentFieldMappers#getMapper. (#31671)
* Rename DocumentFieldMappers#getMapper to getFieldMapper. * Introduce a new DocumentFieldMappers#getMapper that returns a Mapper. * Fix an issue around field aliases in geo suggestion contexts. * Make sure a field alias can refer to a percolate query. * Remove easy-to-fix uses of DocumentFieldMappers#getFieldMapper. * Include alias mappers in DocumentFieldMappers#getMappers. * Make sure we detect conflicts between dynamic object mappers and field aliases. * Throw an exception if aliases are specified as the target of copy_to.
1 parent 65ffdec commit ec65a79

File tree

47 files changed

+564
-350
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+564
-350
lines changed

docs/reference/mapping/types/alias.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ field alias to query over multiple target fields in a single clause.
7474
==== Unsupported APIs
7575

7676
Writes to field aliases are not supported: attempting to use an alias in an index or update request
77-
will result in a failure.
77+
will result in a failure. This also precludes aliases from being the target of `copy_to`.
7878

7979
Because alias names are not present in the document source, aliases cannot be used when performing
8080
source filtering. For example, the following request will return an empty result for `_source`:

modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQuery.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ Query getCandidateMatchesQuery() {
194194
return candidateMatchesQuery;
195195
}
196196

197+
Query getVerifiedMatchesQuery() {
198+
return verifiedMatchesQuery;
199+
}
200+
197201
// Comparing identity here to avoid being cached
198202
// Note that in theory if the same instance gets used multiple times it could still get cached,
199203
// however since we create a new query instance each time we this query this shouldn't happen and thus

modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQueryBuilder.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,13 +618,13 @@ protected Analyzer getWrappedAnalyzer(String fieldName) {
618618
docSearcher.setQueryCache(null);
619619
}
620620

621-
PercolatorFieldMapper percolatorFieldMapper = (PercolatorFieldMapper) docMapper.mappers().getMapper(field);
622-
boolean mapUnmappedFieldsAsString = percolatorFieldMapper.isMapUnmappedFieldAsText();
621+
PercolatorFieldMapper.FieldType pft = (PercolatorFieldMapper.FieldType) fieldType;
622+
String name = this.name != null ? this.name : pft.name();
623623
QueryShardContext percolateShardContext = wrap(context);
624+
PercolateQuery.QueryStore queryStore = createStore(pft.queryBuilderField,
625+
percolateShardContext,
626+
pft.mapUnmappedFieldsAsText);
624627

625-
String name = this.name != null ? this.name : field;
626-
PercolatorFieldMapper.FieldType pft = (PercolatorFieldMapper.FieldType) fieldType;
627-
PercolateQuery.QueryStore queryStore = createStore(pft.queryBuilderField, percolateShardContext, mapUnmappedFieldsAsString);
628628
return pft.percolateQuery(name, queryStore, documents, docSearcher, context.indexVersionCreated());
629629
}
630630

modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,19 @@ public PercolatorFieldMapper build(BuilderContext context) {
136136
fieldType.rangeField = rangeFieldMapper.fieldType();
137137
NumberFieldMapper minimumShouldMatchFieldMapper = createMinimumShouldMatchField(context);
138138
fieldType.minimumShouldMatchField = minimumShouldMatchFieldMapper.fieldType();
139+
fieldType.mapUnmappedFieldsAsText = getMapUnmappedFieldAsText(context.indexSettings());
140+
139141
context.path().remove();
140142
setupFieldType(context);
141143
return new PercolatorFieldMapper(name(), fieldType, defaultFieldType, context.indexSettings(),
142144
multiFieldsBuilder.build(this, context), copyTo, queryShardContext, extractedTermsField,
143145
extractionResultField, queryBuilderField, rangeFieldMapper, minimumShouldMatchFieldMapper);
144146
}
145147

148+
private static boolean getMapUnmappedFieldAsText(Settings indexSettings) {
149+
return INDEX_MAP_UNMAPPED_FIELDS_AS_TEXT_SETTING.get(indexSettings);
150+
}
151+
146152
static KeywordFieldMapper createExtractQueryFieldBuilder(String name, BuilderContext context) {
147153
KeywordFieldMapper.Builder queryMetaDataFieldBuilder = new KeywordFieldMapper.Builder(name);
148154
queryMetaDataFieldBuilder.docValues(false);
@@ -195,6 +201,7 @@ static class FieldType extends MappedFieldType {
195201
MappedFieldType minimumShouldMatchField;
196202

197203
RangeFieldMapper.RangeFieldType rangeField;
204+
boolean mapUnmappedFieldsAsText;
198205

199206
FieldType() {
200207
setIndexOptions(IndexOptions.NONE);
@@ -209,6 +216,7 @@ static class FieldType extends MappedFieldType {
209216
queryBuilderField = ref.queryBuilderField;
210217
rangeField = ref.rangeField;
211218
minimumShouldMatchField = ref.minimumShouldMatchField;
219+
mapUnmappedFieldsAsText = ref.mapUnmappedFieldsAsText;
212220
}
213221

214222
@Override
@@ -327,7 +335,6 @@ Tuple<List<BytesRef>, Map<String, List<byte[]>>> extractTermsAndRanges(IndexRead
327335

328336
}
329337

330-
private final boolean mapUnmappedFieldAsText;
331338
private final Supplier<QueryShardContext> queryShardContext;
332339
private KeywordFieldMapper queryTermsField;
333340
private KeywordFieldMapper extractionResultField;
@@ -348,14 +355,9 @@ Tuple<List<BytesRef>, Map<String, List<byte[]>>> extractTermsAndRanges(IndexRead
348355
this.extractionResultField = extractionResultField;
349356
this.queryBuilderField = queryBuilderField;
350357
this.minimumShouldMatchFieldMapper = minimumShouldMatchFieldMapper;
351-
this.mapUnmappedFieldAsText = getMapUnmappedFieldAsText(indexSettings);
352358
this.rangeFieldMapper = rangeFieldMapper;
353359
}
354360

355-
private static boolean getMapUnmappedFieldAsText(Settings indexSettings) {
356-
return INDEX_MAP_UNMAPPED_FIELDS_AS_TEXT_SETTING.get(indexSettings);
357-
}
358-
359361
@Override
360362
public FieldMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
361363
PercolatorFieldMapper updated = (PercolatorFieldMapper) super.updateFieldType(fullNameToFieldType);
@@ -402,7 +404,7 @@ public Mapper parse(ParseContext context) throws IOException {
402404

403405
Version indexVersion = context.mapperService().getIndexSettings().getIndexVersionCreated();
404406
createQueryBuilderField(indexVersion, queryBuilderField, queryBuilder, context);
405-
Query query = toQuery(queryShardContext, mapUnmappedFieldAsText, queryBuilder);
407+
Query query = toQuery(queryShardContext, isMapUnmappedFieldAsText(), queryBuilder);
406408
processQuery(query, context);
407409
return null;
408410
}
@@ -522,7 +524,7 @@ protected String contentType() {
522524
}
523525

524526
boolean isMapUnmappedFieldAsText() {
525-
return mapUnmappedFieldAsText;
527+
return ((FieldType) fieldType).mapUnmappedFieldsAsText;
526528
}
527529

528530
/**

modules/percolator/src/test/java/org/elasticsearch/percolator/CandidateQueryTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ public void testDuel() throws Exception {
194194
}
195195
Collections.sort(intValues);
196196

197-
MappedFieldType intFieldType = mapperService.documentMapper("type").mappers()
198-
.getMapper("int_field").fieldType();
197+
MappedFieldType intFieldType = mapperService.fullName("int_field");
199198

200199
List<Supplier<Query>> queryFunctions = new ArrayList<>();
201200
queryFunctions.add(MatchNoDocsQuery::new);
@@ -327,8 +326,7 @@ public void testDuel2() throws Exception {
327326
stringValues.add("value2");
328327
stringValues.add("value3");
329328

330-
MappedFieldType intFieldType = mapperService.documentMapper("type").mappers()
331-
.getMapper("int_field").fieldType();
329+
MappedFieldType intFieldType = mapperService.fullName("int_field");
332330
List<int[]> ranges = new ArrayList<>();
333331
ranges.add(new int[]{-5, 5});
334332
ranges.add(new int[]{0, 10});

modules/percolator/src/test/java/org/elasticsearch/percolator/PercolateQueryBuilderTests.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ public class PercolateQueryBuilderTests extends AbstractQueryTestCase<PercolateQ
7575
PercolateQueryBuilder.DOCUMENTS_FIELD.getPreferredName()
7676
};
7777

78-
private static String queryField;
78+
private static String queryField = "field";
79+
private static String aliasField = "alias";
7980
private static String docType;
8081

8182
private String indexedDocumentIndex;
@@ -96,9 +97,11 @@ protected Collection<Class<? extends Plugin>> getPlugins() {
9697
@Override
9798
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
9899
queryField = randomAlphaOfLength(4);
100+
aliasField = randomAlphaOfLength(4);
101+
99102
String docType = "_doc";
100103
mapperService.merge(docType, new CompressedXContent(Strings.toString(PutMappingRequest.buildFromSimplifiedDef(docType,
101-
queryField, "type=percolator"
104+
queryField, "type=percolator", aliasField, "type=alias,path=" + queryField
102105
))), MapperService.MergeReason.MAPPING_UPDATE);
103106
mapperService.merge(docType, new CompressedXContent(Strings.toString(PutMappingRequest.buildFromSimplifiedDef(docType,
104107
STRING_FIELD_NAME, "type=text"
@@ -355,4 +358,21 @@ public void testSerializationFailsUnlessFetched() throws IOException {
355358
builder = rewriteAndFetch(builder, createShardContext());
356359
builder.writeTo(new BytesStreamOutput(10));
357360
}
361+
362+
public void testFieldAlias() throws IOException {
363+
QueryShardContext shardContext = createShardContext();
364+
365+
PercolateQueryBuilder builder = doCreateTestQueryBuilder(false);
366+
QueryBuilder rewrittenBuilder = rewriteAndFetch(builder, shardContext);
367+
PercolateQuery query = (PercolateQuery) rewrittenBuilder.toQuery(shardContext);
368+
369+
PercolateQueryBuilder aliasBuilder = new PercolateQueryBuilder(aliasField,
370+
builder.getDocuments(),
371+
builder.getXContentType());
372+
QueryBuilder rewrittenAliasBuilder = rewriteAndFetch(aliasBuilder, shardContext);
373+
PercolateQuery aliasQuery = (PercolateQuery) rewrittenAliasBuilder.toQuery(shardContext);
374+
375+
assertEquals(query.getCandidateMatchesQuery(), aliasQuery.getCandidateMatchesQuery());
376+
assertEquals(query.getVerifiedMatchesQuery(), aliasQuery.getVerifiedMatchesQuery());
377+
}
358378
}

modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,10 @@ public void testExtractTerms() throws Exception {
224224
public void testExtractRanges() throws Exception {
225225
addQueryFieldMappings();
226226
BooleanQuery.Builder bq = new BooleanQuery.Builder();
227-
Query rangeQuery1 = mapperService.documentMapper("doc").mappers().getMapper("number_field1").fieldType()
227+
Query rangeQuery1 = mapperService.fullName("number_field1")
228228
.rangeQuery(10, 20, true, true, null, null, null, null);
229229
bq.add(rangeQuery1, Occur.MUST);
230-
Query rangeQuery2 = mapperService.documentMapper("doc").mappers().getMapper("number_field1").fieldType()
230+
Query rangeQuery2 = mapperService.fullName("number_field1")
231231
.rangeQuery(15, 20, true, true, null, null, null, null);
232232
bq.add(rangeQuery2, Occur.MUST);
233233

@@ -255,7 +255,7 @@ public void testExtractRanges() throws Exception {
255255
// Range queries on different fields:
256256
bq = new BooleanQuery.Builder();
257257
bq.add(rangeQuery1, Occur.MUST);
258-
rangeQuery2 = mapperService.documentMapper("doc").mappers().getMapper("number_field2").fieldType()
258+
rangeQuery2 = mapperService.fullName("number_field2")
259259
.rangeQuery(15, 20, true, true, null, null, null, null);
260260
bq.add(rangeQuery2, Occur.MUST);
261261

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.elasticsearch.index.IndexService;
4040
import org.elasticsearch.index.mapper.DocumentFieldMappers;
4141
import org.elasticsearch.index.mapper.DocumentMapper;
42-
import org.elasticsearch.index.mapper.FieldMapper;
42+
import org.elasticsearch.index.mapper.Mapper;
4343
import org.elasticsearch.index.shard.ShardId;
4444
import org.elasticsearch.indices.IndicesService;
4545
import org.elasticsearch.indices.TypeMissingException;
@@ -174,19 +174,19 @@ private static Map<String, FieldMappingMetaData> findFieldMappingsByType(Predica
174174
final DocumentFieldMappers allFieldMappers = documentMapper.mappers();
175175
for (String field : request.fields()) {
176176
if (Regex.isMatchAllPattern(field)) {
177-
for (FieldMapper fieldMapper : allFieldMappers) {
178-
addFieldMapper(fieldPredicate, fieldMapper.fieldType().name(), fieldMapper, fieldMappings, request.includeDefaults());
177+
for (Mapper fieldMapper : allFieldMappers) {
178+
addFieldMapper(fieldPredicate, fieldMapper.name(), fieldMapper, fieldMappings, request.includeDefaults());
179179
}
180180
} else if (Regex.isSimpleMatchPattern(field)) {
181-
for (FieldMapper fieldMapper : allFieldMappers) {
182-
if (Regex.simpleMatch(field, fieldMapper.fieldType().name())) {
183-
addFieldMapper(fieldPredicate, fieldMapper.fieldType().name(),
181+
for (Mapper fieldMapper : allFieldMappers) {
182+
if (Regex.simpleMatch(field, fieldMapper.name())) {
183+
addFieldMapper(fieldPredicate, fieldMapper.name(),
184184
fieldMapper, fieldMappings, request.includeDefaults());
185185
}
186186
}
187187
} else {
188188
// not a pattern
189-
FieldMapper fieldMapper = allFieldMappers.getMapper(field);
189+
Mapper fieldMapper = allFieldMappers.getMapper(field);
190190
if (fieldMapper != null) {
191191
addFieldMapper(fieldPredicate, field, fieldMapper, fieldMappings, request.includeDefaults());
192192
} else if (request.probablySingleFieldRequest()) {
@@ -198,7 +198,7 @@ private static Map<String, FieldMappingMetaData> findFieldMappingsByType(Predica
198198
}
199199

200200
private static void addFieldMapper(Predicate<String> fieldPredicate,
201-
String field, FieldMapper fieldMapper, Map<String, FieldMappingMetaData> fieldMappings,
201+
String field, Mapper fieldMapper, Map<String, FieldMappingMetaData> fieldMappings,
202202
boolean includeDefaults) {
203203
if (fieldMappings.containsKey(field)) {
204204
return;
@@ -207,7 +207,7 @@ private static void addFieldMapper(Predicate<String> fieldPredicate,
207207
try {
208208
BytesReference bytes = XContentHelper.toXContent(fieldMapper, XContentType.JSON,
209209
includeDefaults ? includeDefaultsParams : ToXContent.EMPTY_PARAMS, false);
210-
fieldMappings.put(field, new FieldMappingMetaData(fieldMapper.fieldType().name(), bytes));
210+
fieldMappings.put(field, new FieldMappingMetaData(fieldMapper.name(), bytes));
211211
} catch (IOException e) {
212212
throw new ElasticsearchException("failed to serialize XContent of field [" + field + "]", e);
213213
}

server/src/main/java/org/elasticsearch/index/IndexWarmer.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
import org.elasticsearch.index.engine.Engine;
2828
import org.elasticsearch.index.fielddata.IndexFieldData;
2929
import org.elasticsearch.index.fielddata.IndexFieldDataService;
30-
import org.elasticsearch.index.mapper.DocumentMapper;
31-
import org.elasticsearch.index.mapper.FieldMapper;
3230
import org.elasticsearch.index.mapper.MappedFieldType;
3331
import org.elasticsearch.index.mapper.MapperService;
3432
import org.elasticsearch.index.shard.IndexShard;
@@ -121,16 +119,12 @@ private static class FieldDataWarmer implements IndexWarmer.Listener {
121119
public TerminationHandle warmReader(final IndexShard indexShard, final Engine.Searcher searcher) {
122120
final MapperService mapperService = indexShard.mapperService();
123121
final Map<String, MappedFieldType> warmUpGlobalOrdinals = new HashMap<>();
124-
DocumentMapper docMapper = mapperService.documentMapper();
125-
if (docMapper != null) {
126-
for (FieldMapper fieldMapper : docMapper.mappers()) {
127-
final MappedFieldType fieldType = fieldMapper.fieldType();
128-
final String indexName = fieldType.name();
129-
if (fieldType.eagerGlobalOrdinals() == false) {
130-
continue;
131-
}
132-
warmUpGlobalOrdinals.put(indexName, fieldType);
122+
for (MappedFieldType fieldType : mapperService.fieldTypes()) {
123+
final String indexName = fieldType.name();
124+
if (fieldType.eagerGlobalOrdinals() == false) {
125+
continue;
133126
}
127+
warmUpGlobalOrdinals.put(indexName, fieldType);
134128
}
135129
final CountDownLatch latch = new CountDownLatch(warmUpGlobalOrdinals.size());
136130
for (final MappedFieldType fieldType : warmUpGlobalOrdinals.values()) {

server/src/main/java/org/elasticsearch/index/get/ShardGetService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.elasticsearch.index.fieldvisitor.CustomFieldsVisitor;
4040
import org.elasticsearch.index.fieldvisitor.FieldsVisitor;
4141
import org.elasticsearch.index.mapper.DocumentMapper;
42-
import org.elasticsearch.index.mapper.FieldMapper;
42+
import org.elasticsearch.index.mapper.Mapper;
4343
import org.elasticsearch.index.mapper.MapperService;
4444
import org.elasticsearch.index.mapper.RoutingFieldMapper;
4545
import org.elasticsearch.index.mapper.SourceFieldMapper;
@@ -202,7 +202,7 @@ private GetResult innerGetLoadFromStoredFields(String type, String id, String[]
202202

203203
if (gFields != null && gFields.length > 0) {
204204
for (String field : gFields) {
205-
FieldMapper fieldMapper = docMapper.mappers().getMapper(field);
205+
Mapper fieldMapper = docMapper.mappers().getMapper(field);
206206
if (fieldMapper == null) {
207207
if (docMapper.objectMappers().get(field) != null) {
208208
// Only fail if we know it is a object field, missing paths / fields shouldn't fail.

server/src/main/java/org/elasticsearch/index/mapper/DocumentFieldMappers.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
import java.util.Iterator;
2929
import java.util.Map;
3030

31-
public final class DocumentFieldMappers implements Iterable<FieldMapper> {
31+
public final class DocumentFieldMappers implements Iterable<Mapper> {
3232

3333
/** Full field name to mapper */
34-
private final Map<String, FieldMapper> fieldMappers;
34+
private final Map<String, Mapper> fieldMappers;
3535

3636
private final FieldNameAnalyzer indexAnalyzer;
3737
private final FieldNameAnalyzer searchAnalyzer;
@@ -44,8 +44,12 @@ private static void put(Map<String, Analyzer> analyzers, String key, Analyzer va
4444
analyzers.put(key, value);
4545
}
4646

47-
public DocumentFieldMappers(Collection<FieldMapper> mappers, Analyzer defaultIndex, Analyzer defaultSearch, Analyzer defaultSearchQuote) {
48-
Map<String, FieldMapper> fieldMappers = new HashMap<>();
47+
public DocumentFieldMappers(Collection<FieldMapper> mappers,
48+
Collection<FieldAliasMapper> aliasMappers,
49+
Analyzer defaultIndex,
50+
Analyzer defaultSearch,
51+
Analyzer defaultSearchQuote) {
52+
Map<String, Mapper> fieldMappers = new HashMap<>();
4953
Map<String, Analyzer> indexAnalyzers = new HashMap<>();
5054
Map<String, Analyzer> searchAnalyzers = new HashMap<>();
5155
Map<String, Analyzer> searchQuoteAnalyzers = new HashMap<>();
@@ -56,14 +60,32 @@ public DocumentFieldMappers(Collection<FieldMapper> mappers, Analyzer defaultInd
5660
put(searchAnalyzers, fieldType.name(), fieldType.searchAnalyzer(), defaultSearch);
5761
put(searchQuoteAnalyzers, fieldType.name(), fieldType.searchQuoteAnalyzer(), defaultSearchQuote);
5862
}
63+
64+
for (FieldAliasMapper aliasMapper : aliasMappers) {
65+
fieldMappers.put(aliasMapper.name(), aliasMapper);
66+
}
67+
5968
this.fieldMappers = Collections.unmodifiableMap(fieldMappers);
6069
this.indexAnalyzer = new FieldNameAnalyzer(indexAnalyzers);
6170
this.searchAnalyzer = new FieldNameAnalyzer(searchAnalyzers);
6271
this.searchQuoteAnalyzer = new FieldNameAnalyzer(searchQuoteAnalyzers);
6372
}
6473

65-
/** Returns the mapper for the given field */
66-
public FieldMapper getMapper(String field) {
74+
/**
75+
* @deprecated Use {@link DocumentFieldMappers#getMapper} instead. To access a field's
76+
* type information, instead use {@link MapperService#fullName}.
77+
*/
78+
@Deprecated
79+
public FieldMapper getFieldMapper(String field) {
80+
Mapper mapper = getMapper(field);
81+
return (mapper instanceof FieldMapper) ? (FieldMapper) mapper : null;
82+
}
83+
84+
/**
85+
* Returns the leaf mapper associated with this field name. Note that the returned mapper
86+
* could be either a concrete {@link FieldMapper}, or a {@link FieldAliasMapper}.
87+
*/
88+
public Mapper getMapper(String field) {
6789
return fieldMappers.get(field);
6890
}
6991

@@ -87,7 +109,7 @@ public Analyzer searchQuoteAnalyzer() {
87109
return this.searchQuoteAnalyzer;
88110
}
89111

90-
public Iterator<FieldMapper> iterator() {
112+
public Iterator<Mapper> iterator() {
91113
return fieldMappers.values().iterator();
92114
}
93115
}

0 commit comments

Comments
 (0)