Skip to content

Commit d896e62

Browse files
authored
Rewrite range queries with open bounds to exists query (#26160)
* Rewrite range queries with open bounds to exists query This change rewrites range query with open bounds to an exists query that should be faster to execute. Fixes #22640
1 parent 6e085c7 commit d896e62

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import org.apache.lucene.search.MatchNoDocsQuery;
2223
import org.apache.lucene.search.Query;
2324
import org.apache.lucene.search.TermRangeQuery;
2425
import org.apache.lucene.util.BytesRef;
@@ -36,6 +37,7 @@
3637
import org.elasticsearch.common.xcontent.XContentBuilder;
3738
import org.elasticsearch.common.xcontent.XContentParser;
3839
import org.elasticsearch.index.mapper.DateFieldMapper;
40+
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
3941
import org.elasticsearch.index.mapper.MappedFieldType;
4042
import org.elasticsearch.index.mapper.MapperService;
4143
import org.elasticsearch.index.mapper.RangeFieldMapper;
@@ -483,6 +485,21 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws
483485

484486
@Override
485487
protected Query doToQuery(QueryShardContext context) throws IOException {
488+
if (from == null && to == null) {
489+
/**
490+
* Open bounds on both side, we can rewrite to an exists query
491+
* if the {@link FieldNamesFieldMapper} is enabled.
492+
*/
493+
final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType =
494+
(FieldNamesFieldMapper.FieldNamesFieldType) context.getMapperService().fullName(FieldNamesFieldMapper.NAME);
495+
if (fieldNamesFieldType == null) {
496+
return new MatchNoDocsQuery("No mappings yet");
497+
}
498+
// Exists query would fail if the fieldNames field is disabled.
499+
if (fieldNamesFieldType.isEnabled()) {
500+
return ExistsQueryBuilder.newFilter(context, fieldName);
501+
}
502+
}
486503
Query query = null;
487504
MappedFieldType mapper = context.fieldMapper(this.fieldName);
488505
if (mapper != null) {

core/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@
2323

2424
import org.apache.lucene.document.IntPoint;
2525
import org.apache.lucene.document.LongPoint;
26+
import org.apache.lucene.index.Term;
27+
import org.apache.lucene.search.ConstantScoreQuery;
2628
import org.apache.lucene.search.IndexOrDocValuesQuery;
29+
import org.apache.lucene.search.MatchNoDocsQuery;
2730
import org.apache.lucene.search.PointRangeQuery;
2831
import org.apache.lucene.search.Query;
32+
import org.apache.lucene.search.TermQuery;
2933
import org.apache.lucene.search.TermRangeQuery;
3034
import org.elasticsearch.ElasticsearchParseException;
3135
import org.elasticsearch.common.ParsingException;
3236
import org.elasticsearch.common.geo.ShapeRelation;
3337
import org.elasticsearch.common.lucene.BytesRefs;
3438
import org.elasticsearch.index.mapper.DateFieldMapper;
39+
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
3540
import org.elasticsearch.index.mapper.MappedFieldType;
3641
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
3742
import org.elasticsearch.index.mapper.MapperService;
@@ -52,7 +57,6 @@
5257
import static org.hamcrest.Matchers.sameInstance;
5358

5459
public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuilder> {
55-
5660
@Override
5761
protected RangeQueryBuilder doCreateTestQueryBuilder() {
5862
RangeQueryBuilder query;
@@ -122,7 +126,16 @@ protected Map<String, RangeQueryBuilder> getAlternateVersions() {
122126

123127
@Override
124128
protected void doAssertLuceneQuery(RangeQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
125-
if (getCurrentTypes().length == 0 ||
129+
if (queryBuilder.from() == null && queryBuilder.to() == null) {
130+
final Query expectedQuery;
131+
if (getCurrentTypes().length > 0) {
132+
expectedQuery = new ConstantScoreQuery(new TermQuery(new Term(FieldNamesFieldMapper.NAME, queryBuilder.fieldName())));
133+
} else {
134+
expectedQuery = new MatchNoDocsQuery("no mappings yet");
135+
}
136+
assertThat(query, equalTo(expectedQuery));
137+
138+
} else if (getCurrentTypes().length == 0 ||
126139
(queryBuilder.fieldName().equals(DATE_FIELD_NAME) == false
127140
&& queryBuilder.fieldName().equals(INT_FIELD_NAME) == false
128141
&& queryBuilder.fieldName().equals(DATE_RANGE_FIELD_NAME) == false
@@ -425,6 +438,16 @@ protected MappedFieldType.Relation getRelation(QueryRewriteContext queryRewriteC
425438
assertThat(rewrittenRange.fieldName(), equalTo(fieldName));
426439
assertThat(rewrittenRange.from(), equalTo(null));
427440
assertThat(rewrittenRange.to(), equalTo(null));
441+
442+
// Range query with open bounds rewrite to an exists query
443+
final Query luceneQuery = rewrittenRange.toQuery(queryShardContext);
444+
final Query expectedQuery;
445+
if (getCurrentTypes().length > 0) {
446+
expectedQuery = new ConstantScoreQuery(new TermQuery(new Term(FieldNamesFieldMapper.NAME, query.fieldName())));
447+
} else {
448+
expectedQuery = new MatchNoDocsQuery("no mappings yet");
449+
}
450+
assertThat(luceneQuery, equalTo(expectedQuery));
428451
}
429452

430453
public void testRewriteDateToMatchAllWithTimezoneAndFormat() throws IOException {

0 commit comments

Comments
 (0)