Index: src/java/org/apache/lucene/search/HitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/HitQueue.java (revision 911727)
+++ src/java/org/apache/lucene/search/HitQueue.java (working copy)
@@ -78,7 +78,7 @@
@Override
protected final boolean lessThan(ScoreDoc hitA, ScoreDoc hitB) {
- if (hitA.score == hitB.score)
+ if (hitA.score == hitB.score || hitA.doc == Integer.MAX_VALUE || hitB.doc == Integer.MAX_VALUE)
return hitA.doc > hitB.doc;
else
return hitA.score < hitB.score;
Index: src/java/org/apache/lucene/search/TopScoreDocCollector.java
===================================================================
--- src/java/org/apache/lucene/search/TopScoreDocCollector.java (revision 911727)
+++ src/java/org/apache/lucene/search/TopScoreDocCollector.java (working copy)
@@ -28,11 +28,6 @@
* and then (when the scores are tied) docID ascending. When you create an
* instance of this collector you should know in advance whether documents are
* going to be collected in doc Id order or not.
- *
- *
NOTE: The values Float.Nan,
- * Float.NEGATIVE_INFINITY and Float.POSITIVE_INFINITY are
- * not valid scores. This collector will not properly
- * collect hits with such scores.
*/
public abstract class TopScoreDocCollector extends TopDocsCollector {
@@ -46,7 +41,7 @@
public void collect(int doc) throws IOException {
float score = scorer.score();
totalHits++;
- if (score <= pqTop.score) {
+ if (score <= pqTop.score && pqTop.doc != Integer.MAX_VALUE) {
// Since docs are returned in-order (i.e., increasing doc Id), a document
// with equal score to pqTop.score cannot compete since HitQueue favors
// documents with lower doc Ids. Therefore reject those docs too.
Index: src/test/org/apache/lucene/search/TestTopScoreDocCollector.java
===================================================================
--- src/test/org/apache/lucene/search/TestTopScoreDocCollector.java (revision 911727)
+++ src/test/org/apache/lucene/search/TestTopScoreDocCollector.java (working copy)
@@ -24,6 +24,7 @@
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.search.function.CustomScoreQuery;
public class TestTopScoreDocCollector extends LuceneTestCase {
@@ -35,7 +36,6 @@
}
public void testOutOfOrderCollection() throws Exception {
-
Directory dir = new RAMDirectory();
IndexWriter writer = new IndexWriter(dir, null, MaxFieldLength.UNLIMITED);
for (int i = 0; i < 10; i++) {
@@ -50,13 +50,6 @@
"InOrderTopScoreDocCollector"
};
- BooleanQuery bq = new BooleanQuery();
- // Add a Query with SHOULD, since bw.scorer() returns BooleanScorer2
- // which delegates to BS if there are no mandatory clauses.
- bq.add(new MatchAllDocsQuery(), Occur.SHOULD);
- // Set minNrShouldMatch to 1 so that BQ will not optimize rewrite to return
- // the clause instead of BQ.
- bq.setMinimumNumberShouldMatch(1);
IndexSearcher searcher = new IndexSearcher(dir, true);
for (int i = 0; i < inOrder.length; i++) {
TopDocsCollector tdc = TopScoreDocCollector.create(3, inOrder[i]);
@@ -72,4 +65,64 @@
}
}
+ public void testSpecialValues() throws Exception {
+ Directory dir = new RAMDirectory();
+ IndexWriter writer = new IndexWriter(dir, null, MaxFieldLength.UNLIMITED);
+ for (int i = 0; i < 50; i++) {
+ writer.addDocument(new Document());
+ }
+ writer.commit();
+ writer.close();
+
+ boolean[] inOrder = new boolean[] { false, true };
+
+ IndexSearcher searcher = new IndexSearcher(dir, true);
+ for (int i = 0; i < inOrder.length; i++) {
+ // use a larger numDocs value to still have sentinels after query in queue!!!
+
+ // fist check all values for validity, incl NaN
+ TopDocsCollector tdc = TopScoreDocCollector.create(100, inOrder[i]);
+ searcher.search(new CustomScoreQuery(new MatchAllDocsQuery()) {
+ @Override
+ public float customScore(int doc, float subQueryScore, float valSrcScore) {
+ switch (doc % 4) {
+ case 1: return Float.NEGATIVE_INFINITY;
+ case 2: return Float.POSITIVE_INFINITY;
+ case 3: return Float.NaN;
+ default: return 1.0f;
+ }
+ }
+ }, tdc);
+
+ ScoreDoc[] sd = tdc.topDocs().scoreDocs;
+ assertEquals(50, sd.length);
+ for (int j = 0; j < sd.length; j++) {
+ assertTrue("Invalid docid="+sd[j].doc+" for score="+sd[j].score, sd[j].doc >=0 && sd[j].doc != Integer.MAX_VALUE);
+ }
+
+ // then only test infinity values and compare the scored docs (if decreasing)
+ tdc = TopScoreDocCollector.create(100, inOrder[i]);
+ searcher.search(new CustomScoreQuery(new MatchAllDocsQuery()) {
+ @Override
+ public float customScore(int doc, float subQueryScore, float valSrcScore) {
+ switch (doc % 3) {
+ case 1: return Float.NEGATIVE_INFINITY;
+ case 2: return Float.POSITIVE_INFINITY;
+ default: return (float) (doc - 25);
+ }
+ }
+ }, tdc);
+
+ sd = tdc.topDocs().scoreDocs;
+ assertEquals(50, sd.length);
+ for (int j = 1; j < sd.length; j++) {
+ //System.out.println("inOrder="+inOrder[i]+" doc="+sd[j].doc+" score="+sd[j].score);
+ assertTrue("Score must be decreasing", sd[j-1].score >= sd[j].score);
+ if (sd[j-1].score == sd[j].score) {
+ assertTrue("docid must be increasing when score unchanged", sd[j-1].doc < sd[j].doc);
+ }
+ }
+ }
+ }
+
}