diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 0fb9fa168cb..676df6e9cdf 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -352,6 +352,8 @@ Other * LUCENE-9907: Remove dependency on PackedInts#getReader() from the current codecs and move the method to backwards codec. (Ignacio Vera) +* LUCENE-9976: Fix WANDScorer assertion error. (Zach Chen, Adrien Grand, Dawid Weiss) + ======================= Lucene 8.9.0 ======================= API Changes diff --git a/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java index 48e3a2c30f0..3a655fa153f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java @@ -220,7 +220,9 @@ final class WANDScorer extends Scorer { } assert maxScoreSum == leadMaxScore : maxScoreSum + " " + leadMaxScore; - assert minCompetitiveScore == 0 || tailMaxScore < minCompetitiveScore; + assert minCompetitiveScore == 0 + || tailMaxScore < minCompetitiveScore + || tailSize < minShouldMatch; assert doc <= upTo; } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java index 5c92cfde444..3d480c4588a 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java @@ -312,6 +312,55 @@ public class TestWANDScorer extends LuceneTestCase { } } + public void testBasicsWithDisjunctionAndMinShouldMatchAndTailSizeCondition() throws Exception { + try (Directory dir = newDirectory()) { + try (IndexWriter w = + new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(newLogMergePolicy()))) { + for (String[] values : + Arrays.asList( + new String[] {"A", "B"}, // 0 + new String[] {"A"}, // 1 + new String[] {}, // 2 + new String[] {"A", "B", "C"}, // 3 + // 2 "B"s here and the non constant score term query below forces the + // tailMaxScore >= minCompetitiveScore && tailSize < minShouldMatch condition + new String[] {"B", "B"}, // 4 + new String[] {"B", "C"} // 5 + )) { + Document doc = new Document(); + for (String value : values) { + doc.add(new StringField("foo", value, Store.NO)); + } + w.addDocument(doc); + } + + w.forceMerge(1); + } + + try (IndexReader reader = DirectoryReader.open(dir)) { + IndexSearcher searcher = newSearcher(reader); + + Query query = + new BooleanQuery.Builder() + .add(new TermQuery(new Term("foo", "A")), Occur.SHOULD) + .add(new TermQuery(new Term("foo", "B")), Occur.SHOULD) + .add(new TermQuery(new Term("foo", "C")), Occur.SHOULD) + .setMinimumNumberShouldMatch(2) + .build(); + + Scorer scorer = + searcher + .createWeight(searcher.rewrite(query), ScoreMode.TOP_SCORES, 1) + .scorer(searcher.getIndexReader().leaves().get(0)); + + assertEquals(0, scorer.iterator().nextDoc()); + scorer.setMinCompetitiveScore(scorer.score()); + + assertEquals(3, scorer.iterator().nextDoc()); + } + } + } + public void testBasicsWithDisjunctionAndMinShouldMatchAndNonScoringMode() throws Exception { try (Directory dir = newDirectory()) { try (IndexWriter w =