Ensure we rewrite common queries to `match_none` if possible (#25650)
In certain situations we can early terminate and just skip the entire query phase or make the lucene level rewrite very cheap if we can already tell that a query won't match any documents. For instance if there is a single `match_none` ie. due to some range rewrite in a filter or must clause of a boolean query it can just drop all it's other queries since it will never match.
This commit is contained in:
parent
de99610c4e
commit
831dbbf291
|
@ -38,7 +38,10 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded;
|
||||
|
||||
|
@ -438,7 +441,12 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> {
|
|||
changed |= rewriteClauses(queryRewriteContext, mustNotClauses, newBuilder::mustNot);
|
||||
changed |= rewriteClauses(queryRewriteContext, filterClauses, newBuilder::filter);
|
||||
changed |= rewriteClauses(queryRewriteContext, shouldClauses, newBuilder::should);
|
||||
|
||||
// lets do some early termination and prevent any kind of rewriting if we have a mandatory query that is a MatchNoneQueryBuilder
|
||||
Optional<QueryBuilder> any = Stream.concat(newBuilder.mustClauses.stream(), newBuilder.filterClauses.stream())
|
||||
.filter(b -> b instanceof MatchNoneQueryBuilder).findAny();
|
||||
if (any.isPresent()) {
|
||||
return any.get();
|
||||
}
|
||||
if (changed) {
|
||||
newBuilder.adjustPureNegative = adjustPureNegative;
|
||||
newBuilder.minimumShouldMatch = minimumShouldMatch;
|
||||
|
|
|
@ -155,6 +155,9 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
|||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
QueryBuilder rewrite = filterBuilder.rewrite(queryRewriteContext);
|
||||
if (rewrite instanceof MatchNoneQueryBuilder) {
|
||||
return rewrite; // we won't match anyway
|
||||
}
|
||||
if (rewrite != filterBuilder) {
|
||||
return new ConstantScoreQueryBuilder(rewrite);
|
||||
}
|
||||
|
|
|
@ -418,4 +418,23 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
assertEquals(rewrittenAgain, expected);
|
||||
assertEquals(QueryBuilder.rewriteQuery(boolQueryBuilder, createShardContext()), expected);
|
||||
}
|
||||
|
||||
public void testRewriteWithMatchNone() throws IOException {
|
||||
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(new WrapperQueryBuilder(new WrapperQueryBuilder(new MatchNoneQueryBuilder().toString()).toString()));
|
||||
QueryBuilder rewritten = boolQueryBuilder.rewrite(createShardContext());
|
||||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
||||
boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(new TermQueryBuilder("foo","bar"));
|
||||
boolQueryBuilder.filter(new WrapperQueryBuilder(new WrapperQueryBuilder(new MatchNoneQueryBuilder().toString()).toString()));
|
||||
rewritten = boolQueryBuilder.rewrite(createShardContext());
|
||||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
||||
boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(new TermQueryBuilder("foo","bar"));
|
||||
boolQueryBuilder.filter(new BoolQueryBuilder().should(new TermQueryBuilder("foo","bar")).filter(new MatchNoneQueryBuilder()));
|
||||
rewritten = QueryBuilder.rewriteQuery(boolQueryBuilder, createShardContext());
|
||||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,4 +117,10 @@ public class ConstantScoreQueryBuilderTests extends AbstractQueryTestCase<Consta
|
|||
assertEquals(json, 23.0, parsed.boost(), 0.0001);
|
||||
assertEquals(json, 42.0, parsed.innerQuery().boost(), 0.0001);
|
||||
}
|
||||
|
||||
public void testRewriteToMatchNone() throws IOException {
|
||||
ConstantScoreQueryBuilder constantScoreQueryBuilder = new ConstantScoreQueryBuilder(new MatchNoneQueryBuilder());
|
||||
QueryBuilder rewrite = constantScoreQueryBuilder.rewrite(createShardContext());
|
||||
assertEquals(rewrite, new MatchNoneQueryBuilder());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue