diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 4d15969d0b5..682921c8878 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -114,6 +114,8 @@ Improvements with doc values and points. In this case, there is an assumption that the same data is stored in these points and doc values (Mayya Sharipova, Jim Ferenczi, Adrien Grand) +* LUCENE-9446: In BooleanQuery rewrite, always remove MatchAllDocsQuery filter clauses + when possible. (Julie Tibshirani) Bug fixes diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java index 2e2d81b53de..d23bed1096a 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java @@ -315,11 +315,13 @@ public class BooleanQuery extends Query implements Iterable { } } - // remove FILTER clauses that are also MUST clauses - // or that match all documents - if (clauseSets.get(Occur.MUST).size() > 0 && clauseSets.get(Occur.FILTER).size() > 0) { - final Set filters = new HashSet(clauseSets.get(Occur.FILTER)); - boolean modified = filters.remove(new MatchAllDocsQuery()); + // remove FILTER clauses that are also MUST clauses or that match all documents + if (clauseSets.get(Occur.FILTER).size() > 0) { + final Set filters = new HashSet<>(clauseSets.get(Occur.FILTER)); + boolean modified = false; + if (filters.size() > 1 || clauseSets.get(Occur.MUST).isEmpty() == false) { + modified = filters.remove(new MatchAllDocsQuery()); + } modified |= filters.removeAll(clauseSets.get(Occur.MUST)); if (modified) { BooleanQuery.Builder builder = new BooleanQuery.Builder(); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java index 497035b83f8..51ca8e50859 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java @@ -312,12 +312,28 @@ public class TestBooleanRewrites extends LuceneTestCase { .add(new TermQuery(new Term("foo", "baz")), Occur.MUST) .add(new MatchAllDocsQuery(), Occur.FILTER) .build(); - BooleanQuery expected = new BooleanQuery.Builder() + Query expected = new BooleanQuery.Builder() .setMinimumNumberShouldMatch(bq.getMinimumNumberShouldMatch()) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST) .add(new TermQuery(new Term("foo", "baz")), Occur.MUST) .build(); assertEquals(expected, searcher.rewrite(bq)); + + bq = new BooleanQuery.Builder() + .add(new TermQuery(new Term("foo", "bar")), Occur.FILTER) + .add(new MatchAllDocsQuery(), Occur.FILTER) + .build(); + expected = new BoostQuery(new ConstantScoreQuery( + new TermQuery(new Term("foo", "bar"))), 0.0f); + assertEquals(expected, searcher.rewrite(bq)); + + bq = new BooleanQuery.Builder() + .add(new MatchAllDocsQuery(), Occur.FILTER) + .add(new MatchAllDocsQuery(), Occur.FILTER) + .build(); + expected = new BoostQuery(new ConstantScoreQuery( + new MatchAllDocsQuery()), 0.0f); + assertEquals(expected, searcher.rewrite(bq)); } public void testRandom() throws IOException {