Index: src/test/org/apache/lucene/util/TestPriorityQueue.java =================================================================== --- src/test/org/apache/lucene/util/TestPriorityQueue.java (revision 601666) +++ src/test/org/apache/lucene/util/TestPriorityQueue.java (working copy) @@ -107,4 +107,25 @@ assertEquals(3, pq.size()); assertEquals(3, ((Integer) pq.top()).intValue()); } + + public void testInsertWithOverflow() { + int size = 4; + PriorityQueue pq = new IntegerQueue(size); + Integer i1 = new Integer(2); + Integer i2 = new Integer(3); + Integer i3 = new Integer(1); + Integer i4 = new Integer(5); + Integer i5 = new Integer(7); + Integer i6 = new Integer(1); + + assertNull(pq.insertWithOverflow(i1)); + assertNull(pq.insertWithOverflow(i2)); + assertNull(pq.insertWithOverflow(i3)); + assertNull(pq.insertWithOverflow(i4)); + assertTrue(pq.insertWithOverflow(i5) == i3); // i3 should have been dropped + assertTrue(pq.insertWithOverflow(i6) == i6); // i6 should not have been inserted + assertEquals(size, pq.size()); + assertEquals(2, ((Integer) pq.top()).intValue()); + } + } Index: src/java/org/apache/lucene/search/TopDocCollector.java =================================================================== --- src/java/org/apache/lucene/search/TopDocCollector.java (revision 601666) +++ src/java/org/apache/lucene/search/TopDocCollector.java (working copy) @@ -28,12 +28,12 @@ * documents are collected. **/ public class TopDocCollector extends HitCollector { - private int numHits; - private float minScore = 0.0f; + private ScoreDoc reusableSD; + int totalHits; PriorityQueue hq; - + /** Construct to collect a given number of hits. * @param numHits the maximum number of hits to collect */ @@ -42,19 +42,22 @@ } TopDocCollector(int numHits, PriorityQueue hq) { - this.numHits = numHits; this.hq = hq; } // javadoc inherited public void collect(int doc, float score) { - if (score > 0.0f) { - totalHits++; - if (hq.size() < numHits || score >= minScore) { - hq.insert(new ScoreDoc(doc, score)); - minScore = ((ScoreDoc)hq.top()).score; // maintain minScore - } - } + if (score <= 0.0f) { + return; + } + totalHits++; + if (reusableSD == null) { + reusableSD = new ScoreDoc(doc, score); + } else { + reusableSD.doc = doc; + reusableSD.score = score; + } + reusableSD = (ScoreDoc) hq.insertWithOverflow(reusableSD); } /** The total number of documents that matched this query. */ Index: src/java/org/apache/lucene/util/PriorityQueue.java =================================================================== --- src/java/org/apache/lucene/util/PriorityQueue.java (revision 601666) +++ src/java/org/apache/lucene/util/PriorityQueue.java (working copy) @@ -21,9 +21,9 @@ least element can always be found in constant time. Put()'s and pop()'s require log(size) time. */ public abstract class PriorityQueue { - private Object[] heap; private int size; private int maxSize; + protected Object[] heap; /** Determines the ordering of objects in this priority queue. Subclasses must define this one method. */ @@ -54,26 +54,44 @@ * @param element * @return true if element is added, false otherwise. */ - public boolean insert(Object element){ - if(size < maxSize){ + public boolean insert(Object element) { + if (size < maxSize) { put(element); return true; - } - else if(size > 0 && !lessThan(element, top())){ + } else if (size > 0 && !lessThan(element, heap[1])) { heap[1] = element; adjustTop(); return true; + } else { + return false; } - else - return false; - } + } + /** + * insertWithOverflow() is similar to insert(), except its return value: it + * returns the object (if any) that was dropped off the heap because it was + * full. This can be the given parameter (in case it is smaller than the full + * heap's minimum, and couldn't be added) or another object that was + * previously the smallest value in the heap and now has been replaced by a + * larger one. + */ + public Object insertWithOverflow(Object element) { + if (size < maxSize) { + put(element); + return null; + } else if (size > 0 && !lessThan(element, heap[1])) { + Object ret = heap[1]; + heap[1] = element; + adjustTop(); + return ret; + } else { + return element; + } + } + /** Returns the least element of the PriorityQueue in constant time. */ public final Object top() { - if (size > 0) - return heap[1]; - else - return null; + return size > 0 ? heap[1] : null; } /** Removes and returns the least element of the PriorityQueue in log(size) @@ -86,8 +104,8 @@ size--; downHeap(); // adjust heap return result; - } else - return null; + } + return null; } /** Should be called when the Object at top changes values. Still log(n) @@ -101,7 +119,6 @@ downHeap(); } - /** Returns the number of elements currently stored in the PriorityQueue. */ public final int size() { return size; @@ -140,7 +157,7 @@ j = i << 1; k = j + 1; if (k <= size && lessThan(heap[k], heap[j])) { - j = k; + j = k; } } heap[i] = node; // install saved node