| 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 fcae9fc..4c525b7 100644 |
| --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java |
| +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java |
| @@ -21,9 +21,11 @@ import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| +import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Objects; |
| +import java.util.Set; |
| |
| import org.apache.lucene.index.IndexReader; |
| import org.apache.lucene.search.BooleanClause.Occur; |
| @@ -217,13 +219,22 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> { |
| builder.setDisableCoord(isCoordDisabled()); |
| builder.setMinimumNumberShouldMatch(getMinimumNumberShouldMatch()); |
| boolean actuallyRewritten = false; |
| + final Set<BooleanClause> nonScoring = new HashSet<>(clauses.size()); |
| for (BooleanClause clause : this) { |
| Query query = clause.getQuery(); |
| Query rewritten = query.rewrite(reader); |
| if (rewritten != query) { |
| actuallyRewritten = true; |
| } |
| - builder.add(rewritten, clause.getOccur()); |
| + BooleanClause rewrittenClause = new BooleanClause(rewritten, clause.getOccur()); |
| + if (!rewrittenClause.isScoring()) { |
| + if (!nonScoring.add(rewrittenClause)) { |
| + // Drop this duplicate MUST_NOT or FILTER clause |
| + actuallyRewritten = true; |
| + continue; |
| + } |
| + } |
| + builder.add(rewrittenClause); |
| } |
| if (actuallyRewritten) { |
| return builder.build(); |
| diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java |
| index 25c8337..8ee898d 100644 |
| --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java |
| +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java |
| @@ -764,4 +764,60 @@ public class TestBooleanQuery extends LuceneTestCase { |
| searcher.createNormalizedWeight(bq, false).extractTerms(matchingTerms); |
| assertEquals(new HashSet<>(Arrays.asList(a, b, c)), matchingTerms); |
| } |
| + |
| + public void testRewriteToString() throws IOException { |
| + try (Directory directory = newDirectory()) { |
| + try (IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(null))) { |
| + // Just need an empty index so we can create an IndexSearcher below |
| + } |
| + try (IndexReader indexReader = DirectoryReader.open(directory)) { |
| + IndexSearcher searcher = newSearcher(indexReader); |
| + Query query = new BooleanQuery.Builder() |
| + .add(new TermQuery(new Term("field", "a")), Occur.SHOULD) |
| + .add(new TermQuery(new Term("field", "b")), Occur.MUST) |
| + .add(new TermQuery(new Term("field", "c")), Occur.MUST_NOT) |
| + .add(new TermQuery(new Term("field", "d")), Occur.FILTER) |
| + .build(); |
| + assertEquals("a +b -c #d", searcher.rewrite(query).toString("field")); |
| + } |
| + } |
| + } |
| + |
| + public void testRewriteWithDuplicatesToString() throws IOException { |
| + try (Directory directory = newDirectory()) { |
| + try (IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(null))) { |
| + // Just need an empty index so we can create an IndexSearcher below |
| + } |
| + try (IndexReader indexReader = DirectoryReader.open(directory)) { |
| + IndexSearcher searcher = newSearcher(indexReader); |
| + Query query = new BooleanQuery.Builder() |
| + .add(new TermQuery(new Term("field", "a")), Occur.SHOULD) |
| + .add(new TermQuery(new Term("field", "b")), Occur.MUST) |
| + .add(new TermQuery(new Term("field", "c")), Occur.MUST_NOT) |
| + .add(new TermQuery(new Term("field", "d")), Occur.FILTER) |
| + .add(new TermQuery(new Term("field", "a")), Occur.SHOULD) |
| + .add(new TermQuery(new Term("field", "b")), Occur.MUST) |
| + .add(new TermQuery(new Term("field", "c")), Occur.MUST_NOT) |
| + .add(new TermQuery(new Term("field", "d")), Occur.FILTER) |
| + .build(); |
| + assertEquals("a +b -c #d a +b", searcher.rewrite(query).toString("field")); |
| + } |
| + } |
| + } |
| + |
| + public void testRewriteWithDuplicatesReallyOneClauseToString() throws IOException { |
| + try (Directory directory = newDirectory()) { |
| + try (IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(null))) { |
| + // Just need an empty index so we can create an IndexSearcher below |
| + } |
| + try (IndexReader indexReader = DirectoryReader.open(directory)) { |
| + IndexSearcher searcher = newSearcher(indexReader); |
| + Query query = new BooleanQuery.Builder() |
| + .add(new TermQuery(new Term("field", "a")), Occur.FILTER) |
| + .add(new TermQuery(new Term("field", "a")), Occur.FILTER) |
| + .build(); |
| + assertEquals("ConstantScore(a)^0.0", searcher.rewrite(query).toString("field")); |
| + } |
| + } |
| + } |
| } |