From f55180c53e0442ed09bc4a72862c9710caab74e9 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Tue, 11 Oct 2011 08:35:50 +0000 Subject: [PATCH] LUCENE-3503: DisjunctionSumScorer gives slightly different scores when you nextDoc vs advance git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1181659 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 4 + .../lucene/search/DisjunctionSumScorer.java | 4 +- .../lucene/search/TestBooleanQuery.java | 115 +++++++++++++++++- 3 files changed, 119 insertions(+), 4 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index b5895632a01..283f838f48c 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -646,6 +646,10 @@ Bug fixes * LUCENE-3215: SloppyPhraseScorer sometimes computed Infinite freq (Robert Muir, Doron Cohen) +* LUCENE-3503: DisjunctionSumScorer would give slightly different scores + for a document depending if you used nextDoc() versus advance(). + (Mike McCandless, Robert Muir) + New Features * LUCENE-3448: Added FixedBitSet.and(other/DISI), andNot(other/DISI). diff --git a/lucene/src/java/org/apache/lucene/search/DisjunctionSumScorer.java b/lucene/src/java/org/apache/lucene/search/DisjunctionSumScorer.java index 20db4da2b31..91df6e6ed87 100644 --- a/lucene/src/java/org/apache/lucene/search/DisjunctionSumScorer.java +++ b/lucene/src/java/org/apache/lucene/search/DisjunctionSumScorer.java @@ -55,7 +55,7 @@ class DisjunctionSumScorer extends Scorer { /** The number of subscorers that provide the current match. */ protected int nrMatchers = -1; - private float currentScore = Float.NaN; + private double currentScore = Float.NaN; /** Construct a DisjunctionScorer. * @param weight The weight to be used. @@ -195,7 +195,7 @@ class DisjunctionSumScorer extends Scorer { * Initially invalid, until {@link #nextDoc()} is called the first time. */ @Override - public float score() throws IOException { return currentScore; } + public float score() throws IOException { return (float)currentScore; } @Override public int docID() { diff --git a/lucene/src/test/org/apache/lucene/search/TestBooleanQuery.java b/lucene/src/test/org/apache/lucene/search/TestBooleanQuery.java index 1f0726441e4..4edc7173af1 100644 --- a/lucene/src/test/org/apache/lucene/search/TestBooleanQuery.java +++ b/lucene/src/test/org/apache/lucene/search/TestBooleanQuery.java @@ -17,6 +17,9 @@ package org.apache.lucene.search; * limitations under the License. */ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -33,6 +36,7 @@ import org.apache.lucene.search.similarities.SimilarityProvider; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.NamedThreadFactory; +import org.apache.lucene.util._TestUtil; public class TestBooleanQuery extends LuceneTestCase { @@ -183,6 +187,113 @@ public class TestBooleanQuery extends LuceneTestCase { dir1.close(); dir2.close(); } -} - + public void testBS2DisjunctionNextVsAdvance() throws Exception { + final Directory d = newDirectory(); + final RandomIndexWriter w = new RandomIndexWriter(random, d); + final int numDocs = atLeast(300); + for(int docUpto=0;docUpto numTerms) { + terms.remove(random.nextInt(terms.size())); + } + + if (VERBOSE) { + System.out.println(" terms=" + terms); + } + + final BooleanQuery q = new BooleanQuery(); + for(String term : terms) { + q.add(new BooleanClause(new TermQuery(new Term("field", term)), BooleanClause.Occur.SHOULD)); + } + + Weight weight = s.createNormalizedWeight(q); + + Scorer scorer = weight.scorer(s.leafContexts[0], + true, false, null); + + // First pass: just use .nextDoc() to gather all hits + final List hits = new ArrayList(); + while(scorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) { + hits.add(new ScoreDoc(scorer.docID(), scorer.score())); + } + + if (VERBOSE) { + System.out.println(" " + hits.size() + " hits"); + } + + // Now, randomly next/advance through the list and + // verify exact match: + for(int iter2=0;iter2<10;iter2++) { + + weight = s.createNormalizedWeight(q); + scorer = weight.scorer(s.leafContexts[0], + true, false, null); + + if (VERBOSE) { + System.out.println(" iter2=" + iter2); + } + + int upto = -1; + while(upto < hits.size()) { + final int nextUpto; + final int nextDoc; + final int left = hits.size() - upto; + if (left == 1 || random.nextBoolean()) { + // next + nextUpto = 1+upto; + nextDoc = scorer.nextDoc(); + } else { + // advance + int inc = _TestUtil.nextInt(random, 1, left-1); + nextUpto = inc + upto; + nextDoc = scorer.advance(hits.get(nextUpto).doc); + } + + if (nextUpto == hits.size()) { + assertEquals(DocIdSetIterator.NO_MORE_DOCS, nextDoc); + } else { + final ScoreDoc hit = hits.get(nextUpto); + assertEquals(hit.doc, nextDoc); + // Test for precise float equality: + assertTrue("doc " + hit.doc + " has wrong score: expected=" + hit.score + " actual=" + scorer.score(), hit.score == scorer.score()); + } + upto = nextUpto; + } + } + } + + r.close(); + d.close(); + } +}