LUCENE-9446: In boolean rewrite, remove MatchAllDocsQuery filter clauses (#1709)

Previously, we only removed 'match all' FILTER clauses if there was at least one
MUST clause. Now they're also removed if there is another distinct FILTER clause.

This lets boolean queries like `#field:value #*:*` be written to `#field:value`.
This commit is contained in:
Julie Tibshirani 2020-08-04 08:08:10 -07:00 committed by GitHub
parent bd21da6eca
commit b91a161283
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 6 deletions

View File

@ -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

View File

@ -315,11 +315,13 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
}
}
// 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<Query> filters = new HashSet<Query>(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<Query> 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();

View File

@ -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 {