From 63dd719369bd8948ad237f1607a2cff886b66447 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Fri, 11 Aug 2017 09:59:13 +0200 Subject: [PATCH 1/2] 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 --- .../index/query/RangeQueryBuilder.java | 16 +++++++++++ .../index/query/RangeQueryBuilderTests.java | 27 +++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java index 811b6fa198373..531bac9430d25 100644 --- a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java @@ -19,6 +19,7 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.util.BytesRef; @@ -36,6 +37,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.index.mapper.FieldNamesFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.RangeFieldMapper; @@ -483,6 +485,20 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws @Override protected Query doToQuery(QueryShardContext context) throws IOException { + if (from == null && to == null) { + /** + * Open bounds on both side, we can rewrite to an exists query + * if the {@link FieldNamesFieldMapper} is enabled. + */ + final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = + (FieldNamesFieldMapper.FieldNamesFieldType) context.getMapperService().fullName(FieldNamesFieldMapper.NAME); + if (fieldNamesFieldType == null) { + return new MatchNoDocsQuery("No mappings yet"); + } + if (fieldNamesFieldType.isEnabled()) { + return ExistsQueryBuilder.newFilter(context, fieldName); + } + } Query query = null; MappedFieldType mapper = context.fieldMapper(this.fieldName); if (mapper != null) { diff --git a/core/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java index 2f898481ed14a..b57b45c3d7484 100644 --- a/core/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java @@ -23,15 +23,20 @@ import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.LongPoint; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.IndexOrDocValuesQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PointRangeQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermRangeQuery; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.index.mapper.FieldNamesFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType.Relation; import org.elasticsearch.index.mapper.MapperService; @@ -52,7 +57,6 @@ import static org.hamcrest.Matchers.sameInstance; public class RangeQueryBuilderTests extends AbstractQueryTestCase { - @Override protected RangeQueryBuilder doCreateTestQueryBuilder() { RangeQueryBuilder query; @@ -122,7 +126,16 @@ protected Map getAlternateVersions() { @Override protected void doAssertLuceneQuery(RangeQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException { - if (getCurrentTypes().length == 0 || + if (queryBuilder.from() == null && queryBuilder.to() == null) { + final Query expectedQuery; + if (getCurrentTypes().length > 0) { + expectedQuery = new ConstantScoreQuery(new TermQuery(new Term(FieldNamesFieldMapper.NAME, queryBuilder.fieldName()))); + } else { + expectedQuery = new MatchNoDocsQuery("no mappings yet"); + } + assertThat(query, equalTo(expectedQuery)); + + } else if (getCurrentTypes().length == 0 || (queryBuilder.fieldName().equals(DATE_FIELD_NAME) == false && queryBuilder.fieldName().equals(INT_FIELD_NAME) == false && queryBuilder.fieldName().equals(DATE_RANGE_FIELD_NAME) == false @@ -425,6 +438,16 @@ protected MappedFieldType.Relation getRelation(QueryRewriteContext queryRewriteC assertThat(rewrittenRange.fieldName(), equalTo(fieldName)); assertThat(rewrittenRange.from(), equalTo(null)); assertThat(rewrittenRange.to(), equalTo(null)); + + // Range query with open bounds rewrite to an exists query + final Query luceneQuery = rewrittenRange.toQuery(queryShardContext); + final Query expectedQuery; + if (getCurrentTypes().length > 0) { + expectedQuery = new ConstantScoreQuery(new TermQuery(new Term(FieldNamesFieldMapper.NAME, query.fieldName()))); + } else { + expectedQuery = new MatchNoDocsQuery("no mappings yet"); + } + assertThat(luceneQuery, equalTo(expectedQuery)); } public void testRewriteDateToMatchAllWithTimezoneAndFormat() throws IOException { From 9b39ef7b78ccb985958ab30b0b410857791789cf Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Mon, 14 Aug 2017 09:46:06 +0200 Subject: [PATCH 2/2] apply review --- .../java/org/elasticsearch/index/query/RangeQueryBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java index 531bac9430d25..0156710520da8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java @@ -495,6 +495,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException { if (fieldNamesFieldType == null) { return new MatchNoDocsQuery("No mappings yet"); } + // Exists query would fail if the fieldNames field is disabled. if (fieldNamesFieldType.isEnabled()) { return ExistsQueryBuilder.newFilter(context, fieldName); }