Skip to content

Commit 500d533

Browse files
committed
Change query field expansion (#33020)
This commit changes the query field expansion for query parsers to not rely on an hardcoded list of field types. Instead we rely on the type of exception that is thrown by MappedFieldType#termQuery to include/exclude an expanded field. Supersedes #31655 Closes #31798
1 parent 9a3d341 commit 500d533

File tree

4 files changed

+29
-63
lines changed

4 files changed

+29
-63
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.lucene.search.TermInSetQuery;
3636
import org.apache.lucene.search.TermQuery;
3737
import org.apache.lucene.util.BytesRef;
38+
import org.elasticsearch.ElasticsearchParseException;
3839
import org.elasticsearch.common.Nullable;
3940
import org.elasticsearch.common.geo.ShapeRelation;
4041
import org.elasticsearch.common.joda.DateMathParser;
@@ -336,7 +337,13 @@ public boolean isAggregatable() {
336337
/** Generates a query that will only match documents that contain the given value.
337338
* The default implementation returns a {@link TermQuery} over the value bytes,
338339
* boosted by {@link #boost()}.
339-
* @throws IllegalArgumentException if {@code value} cannot be converted to the expected data type */
340+
* @throws IllegalArgumentException if {@code value} cannot be converted to the expected data type or if the field is not searchable
341+
* due to the way it is configured (eg. not indexed)
342+
* @throws ElasticsearchParseException if {@code value} cannot be converted to the expected data type
343+
* @throws UnsupportedOperationException if the field is not searchable regardless of options
344+
* @throws QueryShardException if the field is not searchable regardless of options
345+
*/
346+
// TODO: Standardize exception types
340347
public abstract Query termQuery(Object value, @Nullable QueryShardContext context);
341348

342349
/** Build a constant-scoring query that matches all values. The default implementation uses a

server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,21 @@
1919

2020
package org.elasticsearch.index.search;
2121

22+
import org.elasticsearch.ElasticsearchParseException;
2223
import org.elasticsearch.common.regex.Regex;
23-
import org.elasticsearch.index.mapper.DateFieldMapper;
24-
import org.elasticsearch.index.mapper.DocumentMapper;
25-
import org.elasticsearch.index.mapper.FieldMapper;
26-
import org.elasticsearch.index.mapper.IpFieldMapper;
27-
import org.elasticsearch.index.mapper.KeywordFieldMapper;
2824
import org.elasticsearch.index.mapper.MappedFieldType;
29-
import org.elasticsearch.index.mapper.Mapper;
30-
import org.elasticsearch.index.mapper.MapperService;
31-
import org.elasticsearch.index.mapper.MetadataFieldMapper;
32-
import org.elasticsearch.index.mapper.NumberFieldMapper;
33-
import org.elasticsearch.index.mapper.TextFieldMapper;
3425
import org.elasticsearch.index.query.QueryShardContext;
26+
import org.elasticsearch.index.query.QueryShardException;
3527

3628
import java.util.Collection;
3729
import java.util.HashMap;
38-
import java.util.HashSet;
3930
import java.util.List;
4031
import java.util.Map;
41-
import java.util.Set;
4232

4333
/**
4434
* Helpers to extract and expand field names and boosts
4535
*/
4636
public final class QueryParserHelper {
47-
// Mapping types the "all-ish" query can be executed against
48-
// TODO: Fix the API so that we don't need a hardcoded list of types
49-
private static final Set<String> ALLOWED_QUERY_MAPPER_TYPES;
50-
51-
static {
52-
ALLOWED_QUERY_MAPPER_TYPES = new HashSet<>();
53-
ALLOWED_QUERY_MAPPER_TYPES.add(DateFieldMapper.CONTENT_TYPE);
54-
ALLOWED_QUERY_MAPPER_TYPES.add(IpFieldMapper.CONTENT_TYPE);
55-
ALLOWED_QUERY_MAPPER_TYPES.add(KeywordFieldMapper.CONTENT_TYPE);
56-
for (NumberFieldMapper.NumberType nt : NumberFieldMapper.NumberType.values()) {
57-
ALLOWED_QUERY_MAPPER_TYPES.add(nt.typeName());
58-
}
59-
ALLOWED_QUERY_MAPPER_TYPES.add("scaled_float");
60-
ALLOWED_QUERY_MAPPER_TYPES.add(TextFieldMapper.CONTENT_TYPE);
61-
}
62-
6337
private QueryParserHelper() {}
6438

6539
/**
@@ -85,21 +59,6 @@ public static Map<String, Float> parseFieldsAndWeights(List<String> fields) {
8559
return fieldsAndWeights;
8660
}
8761

88-
/**
89-
* Get a {@link FieldMapper} associated with a field name or null.
90-
* @param mapperService The mapper service where to find the mapping.
91-
* @param field The field name to search.
92-
*/
93-
public static Mapper getFieldMapper(MapperService mapperService, String field) {
94-
for (DocumentMapper mapper : mapperService.docMappers(true)) {
95-
Mapper fieldMapper = mapper.mappers().getMapper(field);
96-
if (fieldMapper != null) {
97-
return fieldMapper;
98-
}
99-
}
100-
return null;
101-
}
102-
10362
public static Map<String, Float> resolveMappingFields(QueryShardContext context,
10463
Map<String, Float> fieldsAndWeights) {
10564
return resolveMappingFields(context, fieldsAndWeights, null);
@@ -136,8 +95,7 @@ public static Map<String, Float> resolveMappingFields(QueryShardContext context,
13695
* @param fieldOrPattern The field name or the pattern to resolve
13796
* @param weight The weight for the field
13897
* @param acceptAllTypes Whether all field type should be added when a pattern is expanded.
139-
* If false, only {@link #ALLOWED_QUERY_MAPPER_TYPES} are accepted and other field types
140-
* are discarded from the query.
98+
* If false, only searchable field types are added.
14199
* @param acceptMetadataField Whether metadata fields should be added when a pattern is expanded.
142100
*/
143101
public static Map<String, Float> resolveMappingField(QueryShardContext context, String fieldOrPattern, float weight,
@@ -152,8 +110,7 @@ public static Map<String, Float> resolveMappingField(QueryShardContext context,
152110
* @param fieldOrPattern The field name or the pattern to resolve
153111
* @param weight The weight for the field
154112
* @param acceptAllTypes Whether all field type should be added when a pattern is expanded.
155-
* If false, only {@link #ALLOWED_QUERY_MAPPER_TYPES} are accepted and other field types
156-
* are discarded from the query.
113+
* If false, only searchable field types are added.
157114
* @param acceptMetadataField Whether metadata fields should be added when a pattern is expanded.
158115
* @param fieldSuffix The suffix name to add to the expanded field names if a mapping exists for that name.
159116
* The original name of the field is kept if adding the suffix to the field name does not point to a valid field
@@ -175,18 +132,20 @@ public static Map<String, Float> resolveMappingField(QueryShardContext context,
175132
continue;
176133
}
177134

178-
// Ignore fields that are not in the allowed mapper types. Some
179-
// types do not support term queries, and thus we cannot generate
180-
// a special query for them.
181-
String mappingType = fieldType.typeName();
182-
if (acceptAllTypes == false && ALLOWED_QUERY_MAPPER_TYPES.contains(mappingType) == false) {
135+
if (acceptMetadataField == false && fieldType.name().startsWith("_")) {
136+
// Ignore metadata fields
183137
continue;
184138
}
185139

186-
// Ignore metadata fields.
187-
Mapper mapper = getFieldMapper(context.getMapperService(), fieldName);
188-
if (acceptMetadataField == false && mapper instanceof MetadataFieldMapper) {
189-
continue;
140+
if (acceptAllTypes == false) {
141+
try {
142+
fieldType.termQuery("", context);
143+
} catch (QueryShardException |UnsupportedOperationException e) {
144+
// field type is never searchable with term queries (eg. geo point): ignore
145+
continue;
146+
} catch (IllegalArgumentException |ElasticsearchParseException e) {
147+
// other exceptions are parsing errors or not indexed fields: keep
148+
}
190149
}
191150
fields.put(fieldName, weight);
192151
}

server/src/test/java/org/elasticsearch/search/query/QueryStringIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,8 @@ public void testFieldAliasOnDisallowedFieldType() throws Exception {
409409
indexRequests.add(client().prepareIndex("test", "_doc", "1").setSource("f3", "text", "f2", "one"));
410410
indexRandom(true, false, indexRequests);
411411

412-
// The wildcard field matches aliases for both a text and boolean field.
413-
// By default, the boolean field should be ignored when building the query.
412+
// The wildcard field matches aliases for both a text and geo_point field.
413+
// By default, the geo_point field should be ignored when building the query.
414414
SearchResponse response = client().prepareSearch("test")
415415
.setQuery(queryStringQuery("text").field("f*_alias"))
416416
.execute().actionGet();

server/src/test/resources/org/elasticsearch/search/query/all-query-index.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@
4646
"format": "yyyy/MM/dd||epoch_millis"
4747
},
4848
"f_bool": {"type": "boolean"},
49-
"f_bool_alias": {
50-
"type": "alias",
51-
"path": "f_bool"
52-
},
5349
"f_byte": {"type": "byte"},
5450
"f_short": {"type": "short"},
5551
"f_int": {"type": "integer"},
@@ -60,6 +56,10 @@
6056
"f_binary": {"type": "binary"},
6157
"f_suggest": {"type": "completion"},
6258
"f_geop": {"type": "geo_point"},
59+
"f_geop_alias": {
60+
"type": "alias",
61+
"path": "f_geop"
62+
},
6363
"f_geos": {"type": "geo_shape"}
6464
}
6565
}

0 commit comments

Comments
 (0)