Skip to content

Commit ffe895e

Browse files
authored
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 46247ff commit ffe895e

File tree

4 files changed

+29
-64
lines changed

4 files changed

+29
-64
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;
@@ -314,7 +315,13 @@ public boolean isAggregatable() {
314315
/** Generates a query that will only match documents that contain the given value.
315316
* The default implementation returns a {@link TermQuery} over the value bytes,
316317
* boosted by {@link #boost()}.
317-
* @throws IllegalArgumentException if {@code value} cannot be converted to the expected data type */
318+
* @throws IllegalArgumentException if {@code value} cannot be converted to the expected data type or if the field is not searchable
319+
* due to the way it is configured (eg. not indexed)
320+
* @throws ElasticsearchParseException if {@code value} cannot be converted to the expected data type
321+
* @throws UnsupportedOperationException if the field is not searchable regardless of options
322+
* @throws QueryShardException if the field is not searchable regardless of options
323+
*/
324+
// TODO: Standardize exception types
318325
public abstract Query termQuery(Object value, @Nullable QueryShardContext context);
319326

320327
/** 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 & 57 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,22 +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-
DocumentMapper mapper = mapperService.documentMapper();
95-
if (mapper != null) {
96-
Mapper fieldMapper = mapper.mappers().getMapper(field);
97-
if (fieldMapper != null) {
98-
return fieldMapper;
99-
}
100-
}
101-
return null;
102-
}
103-
10462
public static Map<String, Float> resolveMappingFields(QueryShardContext context,
10563
Map<String, Float> fieldsAndWeights) {
10664
return resolveMappingFields(context, fieldsAndWeights, null);
@@ -138,8 +96,7 @@ public static Map<String, Float> resolveMappingFields(QueryShardContext context,
13896
* @param fieldOrPattern The field name or the pattern to resolve
13997
* @param weight The weight for the field
14098
* @param acceptAllTypes Whether all field type should be added when a pattern is expanded.
141-
* If false, only {@link #ALLOWED_QUERY_MAPPER_TYPES} are accepted and other field types
142-
* are discarded from the query.
99+
* If false, only searchable field types are added.
143100
* @param acceptMetadataField Whether metadata fields should be added when a pattern is expanded.
144101
*/
145102
public static Map<String, Float> resolveMappingField(QueryShardContext context, String fieldOrPattern, float weight,
@@ -154,8 +111,7 @@ public static Map<String, Float> resolveMappingField(QueryShardContext context,
154111
* @param fieldOrPattern The field name or the pattern to resolve
155112
* @param weight The weight for the field
156113
* @param acceptAllTypes Whether all field type should be added when a pattern is expanded.
157-
* If false, only {@link #ALLOWED_QUERY_MAPPER_TYPES} are accepted and other field types
158-
* are discarded from the query.
114+
* If false, only searchable field types are added.
159115
* @param acceptMetadataField Whether metadata fields should be added when a pattern is expanded.
160116
* @param fieldSuffix The suffix name to add to the expanded field names if a mapping exists for that name.
161117
* The original name of the field is kept if adding the suffix to the field name does not point to a valid field
@@ -177,18 +133,20 @@ public static Map<String, Float> resolveMappingField(QueryShardContext context,
177133
continue;
178134
}
179135

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

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

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

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

433-
// The wildcard field matches aliases for both a text and boolean field.
434-
// By default, the boolean field should be ignored when building the query.
433+
// The wildcard field matches aliases for both a text and geo_point field.
434+
// By default, the geo_point field should be ignored when building the query.
435435
SearchResponse response = client().prepareSearch("test")
436436
.setQuery(queryStringQuery("text").field("f*_alias"))
437437
.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)