Index: lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java =================================================================== --- lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java (revision 1385075) +++ lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java (working copy) @@ -16,15 +16,18 @@ * limitations under the License. */ import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; -import org.apache.lucene.util.LuceneTestCase; - import org.apache.lucene.document.Document; import org.apache.lucene.document.TextField; +import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.FixedBitSet; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util._TestUtil; public class TestBooleanOr extends LuceneTestCase { @@ -162,4 +165,64 @@ dir.close(); super.tearDown(); } + + public void testBooleanScorerMax() throws IOException { + Directory dir = newDirectory(); + RandomIndexWriter riw = new RandomIndexWriter(random(), dir); + + int docCount = atLeast(10000); + + for(int i=0;i optionalScorers, List prohibitedScorers, int maxCoord) throws IOException { super(weight); this.minNrShouldMatch = minNrShouldMatch; - if (optionalScorers != null && optionalScorers.size() > 0) { + // Pre-fill to save the lazy init when collecting + // each sub: + for(int idx=0;idx subs = new ArrayList(); + + if (optionalScorers != null) { for (Scorer scorer : optionalScorers) { - if (scorer.nextDoc() != NO_MORE_DOCS) { - scorers = new SubScorer(scorer, false, false, bucketTable.newCollector(0), scorers); + int doc = scorer.nextDoc(); + if (doc != NO_MORE_DOCS) { + subs.add(new SubScorer(scorer, false, false, new BooleanScorerCollector(false))); } } } - if (prohibitedScorers != null && prohibitedScorers.size() > 0) { + if (prohibitedScorers != null) { for (Scorer scorer : prohibitedScorers) { - if (scorer.nextDoc() != NO_MORE_DOCS) { - scorers = new SubScorer(scorer, false, true, bucketTable.newCollector(PROHIBITED_MASK), scorers); + int doc = scorer.nextDoc(); + if (doc != NO_MORE_DOCS) { + subs.add(new SubScorer(scorer, false, true, new BooleanScorerCollector(true))); } } } + scorers = subs.toArray(new SubScorer[subs.size()]); + coordFactors = new float[optionalScorers.size() + 1]; for (int i = 0; i < coordFactors.length; i++) { coordFactors[i] = disableCoord ? 1.0f : weight.coord(i, maxCoord); } } - // firstDocID is ignored since nextDoc() initializes 'current' @Override public boolean score(Collector collector, int max, int firstDocID) throws IOException { - // Make sure it's only BooleanScorer that calls us: - assert firstDocID == -1; - boolean more; - Bucket tmp; - BucketScorer bs = new BucketScorer(weight); // The internal loop will set the score and doc before calling collect. - collector.setScorer(bs); - do { - bucketTable.first = null; - - while (current != null) { // more queued + collector.setScorer(this); + boolean more = true; - // check prohibited & required - if ((current.bits & PROHIBITED_MASK) == 0) { + while(true) { - // TODO: re-enable this if BQ ever sends us required - // clauses - //&& (current.bits & requiredMask) == requiredMask) { - - // NOTE: Lucene always passes max = - // Integer.MAX_VALUE today, because we never embed - // a BooleanScorer inside another (even though - // that should work)... but in theory an outside - // app could pass a different max so we must check - // it: - if (current.doc >= max){ - tmp = current; - current = current.next; - tmp.next = bucketTable.first; - bucketTable.first = tmp; - continue; - } - - if (current.coord >= minNrShouldMatch) { - bs.score = current.score * coordFactors[current.coord]; - bs.doc = current.doc; - bs.freq = current.coord; - collector.collect(current.doc); - } + final int limit = validCount; + validCount = 0; + + for(int i=0;i= max) { + // Save any too-large docIDs for next time we are + // called: + validSlots[validCount++] = slot; + continue; } - - current = current.next; // pop the queue + + // check prohibited & minShouldMatch + if (!current.prohibited && current.coord >= minNrShouldMatch) { + collector.collect(current.doc); + } } - - if (bucketTable.first != null){ - current = bucketTable.first; - bucketTable.first = current.next; + + if (validCount != 0) { return true; } + if (!more) { + break; + } + // refill the queue more = false; - end += BucketTable.SIZE; - for (SubScorer sub = scorers; sub != null; sub = sub.next) { - int subScorerDocID = sub.scorer.docID(); - if (subScorerDocID != NO_MORE_DOCS) { - more |= sub.scorer.score(sub.collector, end, subScorerDocID); + end += TABLE_SIZE; + + for (SubScorer sub : scorers) { + int doc = sub.scorer.docID(); + if (doc != NO_MORE_DOCS) { + more |= sub.scorer.score(sub.collector, end, doc); } } - current = bucketTable.first; - - } while (current != null || more); + } return false; } @@ -308,7 +254,7 @@ @Override public int docID() { - throw new UnsupportedOperationException(); + return current == null ? -1 : current.doc; } @Override @@ -318,12 +264,12 @@ @Override public float score() { - throw new UnsupportedOperationException(); + return (float) (current.score * coordFactors[current.coord]); } @Override public float freq() throws IOException { - throw new UnsupportedOperationException(); + return current.coord; } @Override @@ -335,7 +281,10 @@ public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("boolean("); - for (SubScorer sub = scorers; sub != null; sub = sub.next) { + for (SubScorer sub : scorers) { + if (sub.prohibited) { + buffer.append('-'); + } buffer.append(sub.scorer.toString()); buffer.append(" "); }