Rewrite queries with no SHOULD clauses and minimumShouldMatch > 0 to a MatchNoDocsQuery.

Closes #14026
This commit is contained in:
Adrien Grand 2024-11-29 14:47:44 +01:00
parent f9869b54d5
commit 06a320a53e
2 changed files with 28 additions and 18 deletions

View File

@ -604,12 +604,10 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
// Important(this can only be processed after nested clauses have been flattened) // Important(this can only be processed after nested clauses have been flattened)
{ {
final Collection<Query> shoulds = clauseSets.get(Occur.SHOULD); final Collection<Query> shoulds = clauseSets.get(Occur.SHOULD);
if (shoulds.size() > 0) {
if (shoulds.size() < minimumNumberShouldMatch) { if (shoulds.size() < minimumNumberShouldMatch) {
return new MatchNoDocsQuery("SHOULD clause count less than minimumNumberShouldMatch"); return new MatchNoDocsQuery("SHOULD clause count less than minimumNumberShouldMatch");
} }
if (shoulds.size() > 0 && shoulds.size() == minimumNumberShouldMatch) {
if (shoulds.size() == minimumNumberShouldMatch) {
BooleanQuery.Builder builder = new BooleanQuery.Builder(); BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (BooleanClause clause : clauses) { for (BooleanClause clause : clauses) {
if (clause.occur() == Occur.SHOULD) { if (clause.occur() == Occur.SHOULD) {
@ -622,7 +620,6 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
return builder.build(); return builder.build();
} }
} }
}
// Inline SHOULD clauses from the only MUST clause // Inline SHOULD clauses from the only MUST clause
{ {

View File

@ -401,14 +401,12 @@ public class TestBooleanRewrites extends LuceneTestCase {
bq = bq =
new BooleanQuery.Builder() new BooleanQuery.Builder()
.setMinimumNumberShouldMatch(random().nextInt(5))
.add(new TermQuery(new Term("foo", "bar")), Occur.MUST) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST)
.add(new TermQuery(new Term("foo", "baz")), Occur.MUST) .add(new TermQuery(new Term("foo", "baz")), Occur.MUST)
.add(new MatchAllDocsQuery(), Occur.FILTER) .add(new MatchAllDocsQuery(), Occur.FILTER)
.build(); .build();
Query expected = Query expected =
new BooleanQuery.Builder() new BooleanQuery.Builder()
.setMinimumNumberShouldMatch(bq.getMinimumNumberShouldMatch())
.add(new TermQuery(new Term("foo", "bar")), Occur.MUST) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST)
.add(new TermQuery(new Term("foo", "baz")), Occur.MUST) .add(new TermQuery(new Term("foo", "baz")), Occur.MUST)
.build(); .build();
@ -476,7 +474,22 @@ public class TestBooleanRewrites extends LuceneTestCase {
Query query = randomBooleanQuery(random()); Query query = randomBooleanQuery(random());
final TopDocs td1 = searcher1.search(query, 100); final TopDocs td1 = searcher1.search(query, 100);
final TopDocs td2 = searcher2.search(query, 100); final TopDocs td2 = searcher2.search(query, 100);
try {
assertEquals(td1, td2); assertEquals(td1, td2);
} catch (AssertionError e) {
System.out.println(query);
Query rewritten = query;
do {
query = rewritten;
rewritten = query.rewrite(searcher1);
System.out.println(rewritten);
TopDocs tdx = searcher2.search(rewritten, 100);
if (td2.totalHits.value() != tdx.totalHits.value()) {
System.out.println("Bad");
}
} while (query != rewritten);
throw e;
}
} }
searcher1.getIndexReader().close(); searcher1.getIndexReader().close();