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/TopFieldDocCollector.java
===================================================================
--- src/java/org/apache/lucene/search/TopFieldDocCollector.java (revision 601666)
+++ src/java/org/apache/lucene/search/TopFieldDocCollector.java (working copy)
@@ -41,12 +41,8 @@
super(numHits, new FieldSortedHitQueue(reader, sort.fields, numHits));
}
- // javadoc inherited
- public void collect(int doc, float score) {
- if (score > 0.0f) {
- totalHits++;
- hq.insert(new FieldDoc(doc, score));
- }
+ protected ScoreDoc newScoreDoc(int doc, float score) {
+ return new FieldDoc(doc, score);
}
// javadoc inherited
Index: src/java/org/apache/lucene/search/FuzzyQuery.java
===================================================================
--- src/java/org/apache/lucene/search/FuzzyQuery.java (revision 601666)
+++ src/java/org/apache/lucene/search/FuzzyQuery.java (working copy)
@@ -104,20 +104,21 @@
FilteredTermEnum enumerator = getEnum(reader);
int maxClauseCount = BooleanQuery.getMaxClauseCount();
ScoreTermQueue stQueue = new ScoreTermQueue(maxClauseCount);
-
+ ScoreTerm reusableST = null;
+
try {
do {
- float minScore = 0.0f;
float score = 0.0f;
Term t = enumerator.term();
if (t != null) {
score = enumerator.difference();
- // terms come in alphabetical order, therefore if queue is full and score
- // not bigger than minScore, we can skip
- if(stQueue.size() < maxClauseCount || score > minScore){
- stQueue.insert(new ScoreTerm(t, score));
- minScore = ((ScoreTerm)stQueue.top()).score; // maintain minScore
+ if (reusableST == null) {
+ reusableST = new ScoreTerm(t, score);
+ } else {
+ reusableST.score = score;
+ reusableST.term = t;
}
+ reusableST = (ScoreTerm) stQueue.insertWithOverflow(reusableST);
}
} while (enumerator.next());
} finally {
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;
+ protected 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,30 @@
}
TopDocCollector(int numHits, PriorityQueue hq) {
- this.numHits = numHits;
this.hq = hq;
}
+ /**
+ * Creates a new ScoreDoc instance. Should be overriden by sub-classes, such
+ * as TopFieldDocCollector which create sub-classes of ScoreDoc.
+ */
+ protected ScoreDoc newScoreDoc(int doc, float score) {
+ return new ScoreDoc(doc, score);
+ }
+
// 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 = newScoreDoc(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/search/FieldSortedHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldSortedHitQueue.java (revision 601666)
+++ src/java/org/apache/lucene/search/FieldSortedHitQueue.java (working copy)
@@ -80,11 +80,16 @@
return maxscore;
}
+ // Update maxscore.
+ private void updateMaxScore(FieldDoc fdoc) {
+ maxscore = Math.max(maxscore, fdoc.score);
+ }
+
// The signature of this method takes a FieldDoc in order to avoid
// the unneeded cast to retrieve the score.
// inherit javadoc
public boolean insert(FieldDoc fdoc) {
- maxscore = Math.max(maxscore,fdoc.score);
+ updateMaxScore(fdoc);
return super.insert(fdoc);
}
@@ -95,6 +100,14 @@
return insert((FieldDoc)fdoc);
}
+ // This overrides PriorityQueue.insertWithOverflow() so that
+ // updateMaxScore(FieldDoc) that keeps track of the score isn't accidentally
+ // bypassed.
+ public Object insertWithOverflow(Object element) {
+ updateMaxScore((FieldDoc) element);
+ return super.insertWithOverflow(element);
+ }
+
/**
* Returns whether a is less relevant than b.
* @param a ScoreDoc
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