diff --git a/server/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java index 0576a68a85b90..9aca0c0fc0d38 100644 --- a/server/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java @@ -137,47 +137,42 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro return new SpanMultiTermQueryBuilder(subQuery).queryName(queryName).boost(boost); } - public static class TopTermSpanBooleanQueryRewriteWithMaxClause extends SpanMultiTermQueryWrapper.SpanRewriteMethod { - - private MultiTermQuery multiTermQuery; + static class TopTermSpanBooleanQueryRewriteWithMaxClause extends SpanMultiTermQueryWrapper.SpanRewriteMethod { private final long maxExpansions; - TopTermSpanBooleanQueryRewriteWithMaxClause(long max) { - maxExpansions = max; + TopTermSpanBooleanQueryRewriteWithMaxClause() { + this.maxExpansions = BooleanQuery.getMaxClauseCount(); } @Override public SpanQuery rewrite(IndexReader reader, MultiTermQuery query) throws IOException { - multiTermQuery = query; - return (SpanQuery) this.delegate.rewrite(reader, multiTermQuery); - } - - final ScoringRewrite> delegate = new ScoringRewrite>() { - - @Override - protected List getTopLevelBuilder() { - return new ArrayList(); - } + final MultiTermQuery.RewriteMethod delegate = new ScoringRewrite>() { + @Override + protected List getTopLevelBuilder() { + return new ArrayList(); + } - @Override - protected Query build(List builder) { - return new SpanOrQuery((SpanQuery[]) builder.toArray(new SpanQuery[builder.size()])); - } + @Override + protected Query build(List builder) { + return new SpanOrQuery((SpanQuery[]) builder.toArray(new SpanQuery[builder.size()])); + } - @Override - protected void checkMaxClauseCount(int count) { - if (count > maxExpansions) { - throw new ElasticsearchException("[" + multiTermQuery.toString() + " ] " + - "exceeds maxClauseCount [ Boolean maxClauseCount is set to " + BooleanQuery.getMaxClauseCount() + "]"); + @Override + protected void checkMaxClauseCount(int count) { + if (count > maxExpansions) { + throw new RuntimeException("[" + query.toString() + " ] " + + "exceeds maxClauseCount [ Boolean maxClauseCount is set to " + BooleanQuery.getMaxClauseCount() + "]"); + } } - } - @Override - protected void addClause(List topLevel, Term term, int docCount, float boost, TermContext states) { - SpanTermQuery q = new SpanTermQuery(term, states); - topLevel.add(q); - } - }; + @Override + protected void addClause(List topLevel, Term term, int docCount, float boost, TermContext states) { + SpanTermQuery q = new SpanTermQuery(term, states); + topLevel.add(q); + } + }; + return (SpanQuery) delegate.rewrite(reader, query); + } } @Override @@ -222,6 +217,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException { QueryParsers.parseRewriteMethod(prefixBuilder.rewrite(), null, LoggingDeprecationHandler.INSTANCE); prefixQuery.setRewriteMethod(rewriteMethod); } + subQuery = prefixQuery; spanQuery = new SpanMultiTermQueryWrapper<>(prefixQuery); } else { String origFieldName = ((PrefixQueryBuilder) multiTermQueryBuilder).fieldName(); @@ -240,9 +236,12 @@ protected Query doToQuery(QueryShardContext context) throws IOException { + MultiTermQuery.class.getName() + " but was " + subQuery.getClass().getName()); } spanQuery = new SpanMultiTermQueryWrapper<>((MultiTermQuery) subQuery); - if (((MultiTermQuery) subQuery).getRewriteMethod() instanceof TopTermsRewrite == false) { - ((SpanMultiTermQueryWrapper) spanQuery).setRewriteMethod(new - TopTermSpanBooleanQueryRewriteWithMaxClause(BooleanQuery.getMaxClauseCount())); + } + if (subQuery instanceof MultiTermQuery) { + MultiTermQuery multiTermQuery = (MultiTermQuery) subQuery; + SpanMultiTermQueryWrapper wrapper = (SpanMultiTermQueryWrapper) spanQuery; + if (multiTermQuery.getRewriteMethod() instanceof TopTermsRewrite == false) { + wrapper.setRewriteMethod(new TopTermSpanBooleanQueryRewriteWithMaxClause()); } } if (boost != AbstractQueryBuilder.DEFAULT_BOOST) { diff --git a/server/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java index fae66dd68bc0c..c93df5b751942 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java @@ -19,7 +19,13 @@ package org.elasticsearch.index.query; +import org.apache.lucene.analysis.core.WhitespaceAnalyzer; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.TextField; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PrefixQuery; @@ -30,6 +36,7 @@ import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.search.spans.SpanTermQuery; +import org.apache.lucene.store.Directory; import org.elasticsearch.Version; import org.elasticsearch.common.Strings; import org.elasticsearch.common.compress.CompressedXContent; @@ -41,6 +48,7 @@ import java.io.IOException; +import static java.util.Collections.singleton; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; @@ -251,14 +259,37 @@ public void testDefaultMaxRewriteBuilder() throws Exception { MultiTermQuery.RewriteMethod rewriteMethod = ((SpanMultiTermQueryWrapper)query).getRewriteMethod(); assertTrue(rewriteMethod instanceof SpanMultiTermQueryBuilder.TopTermSpanBooleanQueryRewriteWithMaxClause); } + } + public void testTermExpansionExceptionOnSpanFailure() throws Exception { + try (Directory directory = newDirectory()) { + try (RandomIndexWriter iw = new RandomIndexWriter(random(), directory, new WhitespaceAnalyzer())) { + for (int i = 0; i < 3; i++) { + iw.addDocument(singleton(new TextField("body", "foo bar" + Integer.toString(i), Field.Store.NO))); + } + try (IndexReader reader = iw.getReader()) { + int origBoolMaxClauseCount = BooleanQuery.getMaxClauseCount(); + BooleanQuery.setMaxClauseCount(1); + try { + QueryBuilder queryBuilder = new SpanMultiTermQueryBuilder( + QueryBuilders.prefixQuery("body", "bar") + ); + Query query = queryBuilder.toQuery(createShardContext(reader)); + RuntimeException exc = expectThrows(RuntimeException.class, () -> query.rewrite(reader)); + assertThat(exc.getMessage(), containsString("maxClauseCount")); + + } finally { + BooleanQuery.setMaxClauseCount(origBoolMaxClauseCount); + } + } + } + } } public void testTopNMultiTermsRewriteInsideSpan() throws Exception { - - Query query = QueryBuilders.spanMultiTermQueryBuilder(QueryBuilders.prefixQuery("foo", "b").rewrite - ("top_terms_boost_2000")). - toQuery(createShardContext()); + Query query = QueryBuilders.spanMultiTermQueryBuilder( + QueryBuilders.prefixQuery("foo", "b").rewrite("top_terms_boost_2000") + ).toQuery(createShardContext()); if (query instanceof SpanBoostQuery) { query = ((SpanBoostQuery)query).getQuery(); diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index 5dd669119e56d..c3df8d778a722 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -1825,31 +1825,4 @@ public void testRangeQueryRangeFields_24744() throws Exception { SearchResponse searchResponse = client().prepareSearch("test").setQuery(range).get(); assertHitCount(searchResponse, 1); } - - public void testTermExpansionExceptionOnSpanFailure() throws ExecutionException, InterruptedException { - Settings.Builder builder = Settings.builder(); - builder.put(SETTING_NUMBER_OF_SHARDS, 1).build(); - - createIndex("test", builder.build()); - ArrayList reqs = new ArrayList<>(); - int origBoolMaxClauseCount = BooleanQuery.getMaxClauseCount(); - try { - BooleanQuery.setMaxClauseCount(2); - for (int i = 0; i < BooleanQuery.getMaxClauseCount() + 1; i++) { - reqs.add(client().prepareIndex("test", "_doc", Integer.toString(i)).setSource("body", "foo" + - Integer.toString(i) + " bar baz")); - } - indexRandom(true, false, reqs); - - QueryBuilder queryBuilder = new SpanNearQueryBuilder(new SpanMultiTermQueryBuilder(QueryBuilders.wildcardQuery - ("body", "f*")), 0).addClause(new SpanTermQueryBuilder("body", "bar")); - - expectThrows(ElasticsearchException.class, () -> - client().prepareSearch().setIndices("test").setQuery(queryBuilder).get()); - } finally { - BooleanQuery.setMaxClauseCount(origBoolMaxClauseCount); - } - - } - }