LUCENE-1614: switch next -> nextDoc, skipTo -> advance, doc -> docID in DISI

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@782410 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-06-07 16:58:41 +00:00
parent 9dbff2618f
commit a93e2c41b0
49 changed files with 1528 additions and 1006 deletions

View File

@ -35,7 +35,7 @@ Changes in backwards compatibility policy
code to implement this method. If you already extend
IndexSearcher, no further changes are needed to use Collector.
Finally, the values Float.Nan, Float.NEGATIVE_INFINITY and
Finally, the values Float.NaN, Float.NEGATIVE_INFINITY and
Float.POSITIVE_INFINITY are not valid scores. Lucene uses these
values internally in certain places, so if you have hits with such
scores it will cause problems. (Shai Erera via Mike McCandless)
@ -173,6 +173,17 @@ API Changes
require up front specification of enablePositionIncrement (Mike
McCandless)
18. LUCENE-1614: DocIdSetIterator's next() and skipTo() were deprecated in favor
of the new nextDoc() and advance(). The new methods return the doc Id they
landed on, saving an extra call to doc() in most cases.
For easy migration of the code, you can change the calls to next() to
nextDoc() != DocIdSetIterator.NO_MORE_DOCS and similarly for skipTo().
However it is advised that you take advantage of the returned doc ID and not
call doc() following those two.
Also, doc() was deprecated in favor of docID(). docID() should return -1 or
NO_MORE_DOCS if nextDoc/advance were not called yet, or NO_MORE_DOCS if the
iterator has exhausted. Otherwise it should return the current doc ID.
(Shai Erera via Mike McCandless)
Bug fixes

View File

@ -42,7 +42,7 @@
<property name="Name" value="Lucene"/>
<property name="dev.version" value="2.9-dev"/>
<property name="version" value="${dev.version}"/>
<property name="compatibility.tag" value="lucene_2_4_back_compat_tests_20090607a"/>
<property name="compatibility.tag" value="lucene_2_4_back_compat_tests_20090607b"/>
<property name="spec.version" value="${version}"/>
<property name="year" value="2000-${current.year}"/>
<property name="final.name" value="lucene-${name}-${version}"/>

View File

@ -20,16 +20,12 @@ package org.apache.lucene.misc;
import junit.framework.TestCase;
import java.util.*;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.NoLockFactory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
@ -77,7 +73,7 @@ public class ChainedFilterTest extends TestCase {
query = bq;
// date filter matches everything too
Date pastTheEnd = parseDate("2099 Jan 1");
//Date pastTheEnd = parseDate("2099 Jan 1");
// dateFilter = DateFilter.Before("date", pastTheEnd);
// just treat dates as strings and select the whole range for now...
dateFilter = new RangeFilter("date","","ZZZZ",true,true);
@ -94,15 +90,17 @@ public class ChainedFilterTest extends TestCase {
final Filter f = chain[i];
// create old BitSet-based Filter as wrapper
oldFilters[i] = new Filter() {
/** @deprecated */
public BitSet bits(IndexReader reader) throws IOException {
BitSet bits = new BitSet(reader.maxDoc());
DocIdSetIterator it = f.getDocIdSet(reader).iterator();
while(it.next()) {
bits.set(it.doc());
DocIdSetIterator it = f.getDocIdSet(reader).iterator();
int doc;
while((doc = it.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
bits.set(doc);
}
return bits;
}
};
};
}
return oldFilters;
}
@ -211,37 +209,36 @@ public class ChainedFilterTest extends TestCase {
}
}
/*
private Date parseDate(String s) throws ParseException {
return new SimpleDateFormat("yyyy MMM dd", Locale.US).parse(s);
}
*/
public void testWithCachingFilter() throws Exception {
for (int mode = 0; mode < 2; mode++) {
boolean old = (mode==0);
Directory dir = new RAMDirectory();
Analyzer analyzer = new WhitespaceAnalyzer();
Directory dir = new RAMDirectory();
Analyzer analyzer = new WhitespaceAnalyzer();
IndexWriter writer = new IndexWriter(dir, analyzer, true, MaxFieldLength.LIMITED);
writer.close();
IndexWriter writer = new IndexWriter(dir, analyzer, true, MaxFieldLength.LIMITED);
writer.close();
Searcher searcher = new IndexSearcher(dir);
Searcher searcher = new IndexSearcher(dir);
Query query = new TermQuery(new Term("none", "none"));
Query query = new TermQuery(new Term("none", "none"));
QueryWrapperFilter queryFilter = new QueryWrapperFilter(query);
CachingWrapperFilter cachingFilter = new CachingWrapperFilter(queryFilter);
QueryWrapperFilter queryFilter = new QueryWrapperFilter(query);
CachingWrapperFilter cachingFilter = new CachingWrapperFilter(queryFilter);
searcher.search(query, cachingFilter, 1);
searcher.search(query, cachingFilter, 1);
CachingWrapperFilter cachingFilter2 = new CachingWrapperFilter(queryFilter);
Filter[] chain = new Filter[2];
chain[0] = cachingFilter;
chain[1] = cachingFilter2;
ChainedFilter cf = new ChainedFilter(chain);
CachingWrapperFilter cachingFilter2 = new CachingWrapperFilter(queryFilter);
Filter[] chain = new Filter[2];
chain[0] = cachingFilter;
chain[1] = cachingFilter2;
ChainedFilter cf = new ChainedFilter(chain);
// throws java.lang.ClassCastException: org.apache.lucene.util.OpenBitSet cannot be cast to java.util.BitSet
searcher.search(new MatchAllDocsQuery(), cf, 1);
}
// throws java.lang.ClassCastException: org.apache.lucene.util.OpenBitSet cannot be cast to java.util.BitSet
searcher.search(new MatchAllDocsQuery(), cf, 1);
}
}

View File

@ -991,11 +991,11 @@ final class DocumentsWriter {
int limit = ((Integer) entry.getValue()).intValue();
Weight weight = query.weight(searcher);
Scorer scorer = weight.scorer(reader);
while(scorer.next()) {
final int docID = scorer.doc();
if (docIDStart + docID >= limit)
while(true) {
int doc = scorer.nextDoc();
if (((long) docIDStart) + doc >= limit)
break;
reader.deleteDocument(docID);
reader.deleteDocument(doc);
any = true;
}
}

View File

@ -217,13 +217,15 @@ public class BooleanQuery extends Query {
}
}
/** @return Returns BooleanScorer2 that uses and provides skipTo(),
* and scores documents in document number order.
/**
* @return Returns BooleanScorer2 that uses and provides advance(), and
* scores documents in document number order.
*/
public Scorer scorer(IndexReader reader) throws IOException {
// TODO (3.0): instantiate either BS or BS2, according to
// allowDocsOutOfOrder (basically, try to inline BS2.score(Collector)'s
// logic.
BooleanScorer2 result = new BooleanScorer2(similarity,
minNrShouldMatch,
allowDocsOutOfOrder);

View File

@ -18,8 +18,11 @@ package org.apache.lucene.search;
*/
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.lucene.index.IndexReader;
/* Description from Doug Cutting (excerpted from
* LUCENE-1483):
*
@ -54,30 +57,105 @@ import org.apache.lucene.index.IndexReader;
* updates for the optional terms. */
final class BooleanScorer extends Scorer {
private SubScorer scorers = null;
private BucketTable bucketTable = new BucketTable();
private static final class BooleanScorerCollector extends Collector {
private BucketTable bucketTable;
private int mask;
private Scorer scorer;
public BooleanScorerCollector(int mask, BucketTable bucketTable) {
this.mask = mask;
this.bucketTable = bucketTable;
}
public final void collect(final int doc) throws IOException {
final BucketTable table = bucketTable;
final int i = doc & BucketTable.MASK;
Bucket bucket = table.buckets[i];
if (bucket == null)
table.buckets[i] = bucket = new Bucket();
if (bucket.doc != doc) { // invalid bucket
bucket.doc = doc; // set doc
bucket.score = scorer.score(); // initialize score
bucket.bits = mask; // initialize mask
bucket.coord = 1; // initialize coord
private int maxCoord = 1;
private float[] coordFactors = null;
private int requiredMask = 0;
private int prohibitedMask = 0;
private int nextMask = 1;
private final int minNrShouldMatch;
BooleanScorer(Similarity similarity) {
this(similarity, 1);
bucket.next = table.first; // push onto valid list
table.first = bucket;
} else { // valid bucket
bucket.score += scorer.score(); // increment score
bucket.bits |= mask; // add bits in mask
bucket.coord++; // increment coord
}
}
public void setNextReader(IndexReader reader, int docBase) {
// not needed by this implementation
}
public void setScorer(Scorer scorer) throws IOException {
this.scorer = scorer;
}
}
BooleanScorer(Similarity similarity, int minNrShouldMatch) {
super(similarity);
this.minNrShouldMatch = minNrShouldMatch;
// An internal class which is used in score(Collector, int) for setting the
// current score. This is required since Collector exposes a setScorer method
// and implementations that need the score will call scorer.score().
// Therefore the only methods that are implemented are score() and doc().
private static final class BucketScorer extends Scorer {
float score;
int doc = NO_MORE_DOCS;
public BucketScorer() { super(null); }
public int advance(int target) throws IOException { return NO_MORE_DOCS; }
/** @deprecated use {@link #docID()} instead. */
public int doc() { return doc; }
public int docID() { return doc; }
public Explanation explain(int doc) throws IOException { return null; }
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException { return false; }
public int nextDoc() throws IOException { return NO_MORE_DOCS; }
public float score() throws IOException { return score; }
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException { return false; }
}
static final class Bucket {
int doc = -1; // tells if bucket is valid
float score; // incremental score
int bits; // used for bool constraints
int coord; // count of terms in score
Bucket next; // next valid bucket
}
/** A simple hash table of document scores within a range. */
static final class BucketTable {
public static final int SIZE = 1 << 11;
public static final int MASK = SIZE - 1;
final Bucket[] buckets = new Bucket[SIZE];
Bucket first = null; // head of valid list
public BucketTable() {}
public Collector newCollector(int mask) {
return new BooleanScorerCollector(mask, this);
}
public final int size() { return SIZE; }
}
static final class SubScorer {
public Scorer scorer;
public boolean done;
public boolean required = false;
public boolean prohibited = false;
public Collector collector;
@ -87,41 +165,52 @@ final class BooleanScorer extends Scorer {
Collector collector, SubScorer next)
throws IOException {
this.scorer = scorer;
this.done = !scorer.next();
this.required = required;
this.prohibited = prohibited;
this.collector = collector;
this.next = next;
}
}
private SubScorer scorers = null;
private BucketTable bucketTable = new BucketTable();
private int maxCoord = 1;
private final float[] coordFactors;
private int requiredMask = 0;
private int prohibitedMask = 0;
private int nextMask = 1;
private final int minNrShouldMatch;
private int end;
private Bucket current;
private int doc = -1;
final void add(Scorer scorer, boolean required, boolean prohibited)
throws IOException {
int mask = 0;
if (required || prohibited) {
if (nextMask == 0) {
throw new IndexOutOfBoundsException(
"More than 32 required/prohibited clauses in query.");
BooleanScorer(Similarity similarity, int minNrShouldMatch,
List optionalScorers, List prohibitedScorers) throws IOException {
super(similarity);
this.minNrShouldMatch = minNrShouldMatch;
if (optionalScorers != null && optionalScorers.size() > 0) {
for (Iterator si = optionalScorers.iterator(); si.hasNext();) {
Scorer scorer = (Scorer) si.next();
maxCoord++;
if (scorer.nextDoc() != NO_MORE_DOCS) {
scorers = new SubScorer(scorer, false, false, bucketTable.newCollector(0), scorers);
}
}
}
if (prohibitedScorers != null && prohibitedScorers.size() > 0) {
for (Iterator si = prohibitedScorers.iterator(); si.hasNext();) {
Scorer scorer = (Scorer) si.next();
int mask = nextMask;
nextMask = nextMask << 1;
prohibitedMask |= mask; // update prohibited mask
if (scorer.nextDoc() != NO_MORE_DOCS) {
scorers = new SubScorer(scorer, false, true, bucketTable.newCollector(mask), scorers);
}
}
mask = nextMask;
nextMask = nextMask << 1;
}
if (!prohibited) {
maxCoord++;
if (required) {
requiredMask |= mask; // update required mask
}
} else {
// prohibited
prohibitedMask |= mask; // update prohibited mask
}
scorers = new SubScorer(scorer, required, prohibited,
bucketTable.newCollector(mask), scorers);
}
private final void computeCoordFactors() {
coordFactors = new float[maxCoord];
Similarity sim = getSimilarity();
for (int i = 0; i < maxCoord; i++) {
@ -129,31 +218,10 @@ final class BooleanScorer extends Scorer {
}
}
private int end;
private Bucket current;
/** @deprecated use {@link #score(Collector)} instead. */
public void score(HitCollector hc) throws IOException {
score(new HitCollectorWrapper(hc));
}
public void score(Collector collector) throws IOException {
next();
score(collector, Integer.MAX_VALUE);
}
/** @deprecated use {@link #score(Collector, int)} instead. */
protected boolean score(HitCollector hc, int max) throws IOException {
return score(new HitCollectorWrapper(hc), max);
}
protected boolean score(Collector collector, int max) throws IOException {
if (coordFactors == null) {
computeCoordFactors();
}
// firstDocID is ignored since nextDoc() initializes 'current'
protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
boolean more;
Bucket tmp;
BucketScorer bs = new BucketScorer();
// The internal loop will set the score and doc before calling collect.
collector.setScorer(bs);
@ -194,10 +262,9 @@ final class BooleanScorer extends Scorer {
more = false;
end += BucketTable.SIZE;
for (SubScorer sub = scorers; sub != null; sub = sub.next) {
if (!sub.done) {
sub.done = !sub.scorer.score(sub.collector, end);
if (!sub.done)
more = true;
int subScorerDocID = sub.scorer.docID();
if (subScorerDocID != NO_MORE_DOCS) {
more |= sub.scorer.score(sub.collector, end, subScorerDocID);
}
}
current = bucketTable.first;
@ -207,9 +274,32 @@ final class BooleanScorer extends Scorer {
return false;
}
public int doc() { return current.doc; }
/** @deprecated use {@link #score(Collector, int)} instead. */
protected boolean score(HitCollector hc, int max) throws IOException {
return score(new HitCollectorWrapper(hc), max, docID());
}
public int advance(int target) throws IOException {
throw new UnsupportedOperationException();
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return current.doc; }
public int docID() {
return doc;
}
public Explanation explain(int doc) {
throw new UnsupportedOperationException();
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
boolean more;
do {
while (bucketTable.first != null) { // more queued
@ -220,7 +310,7 @@ final class BooleanScorer extends Scorer {
if ((current.bits & prohibitedMask) == 0 &&
(current.bits & requiredMask) == requiredMask &&
current.coord >= minNrShouldMatch) {
return true;
return doc = current.doc;
}
}
@ -230,134 +320,36 @@ final class BooleanScorer extends Scorer {
for (SubScorer sub = scorers; sub != null; sub = sub.next) {
Scorer scorer = sub.scorer;
sub.collector.setScorer(scorer);
while (!sub.done && scorer.doc() < end) {
sub.collector.collect(scorer.doc());
sub.done = !scorer.next();
}
if (!sub.done) {
more = true;
int doc = scorer.docID();
while (doc < end) {
sub.collector.collect(doc);
doc = scorer.nextDoc();
}
more |= (doc != NO_MORE_DOCS);
}
} while (bucketTable.first != null || more);
return false;
return doc = NO_MORE_DOCS;
}
public float score() {
if (coordFactors == null) {
computeCoordFactors();
}
return current.score * coordFactors[current.coord];
}
static final class Bucket {
int doc = -1; // tells if bucket is valid
float score; // incremental score
int bits; // used for bool constraints
int coord; // count of terms in score
Bucket next; // next valid bucket
public void score(Collector collector) throws IOException {
score(collector, Integer.MAX_VALUE, nextDoc());
}
// An internal class which is used in score(Collector, int) for setting the
// current score. This is required since Collector exposes a setScorer method
// and implementations that need the score will call scorer.score().
// Therefore the only methods that are implemented are score() and doc().
private static final class BucketScorer extends Scorer {
float score;
int doc;
public BucketScorer() {
super(null);
}
public Explanation explain(int doc) throws IOException {
return null;
}
public float score() throws IOException {
return score;
}
public int doc() {
return doc;
}
public boolean next() throws IOException {
return false;
}
public boolean skipTo(int target) throws IOException {
return false;
}
/** @deprecated use {@link #score(Collector)} instead. */
public void score(HitCollector hc) throws IOException {
score(new HitCollectorWrapper(hc));
}
/** A simple hash table of document scores within a range. */
static final class BucketTable {
public static final int SIZE = 1 << 11;
public static final int MASK = SIZE - 1;
final Bucket[] buckets = new Bucket[SIZE];
Bucket first = null; // head of valid list
public BucketTable() {}
public final int size() { return SIZE; }
public Collector newCollector(int mask) {
return new BooleanScorerCollector(mask, this);
}
}
private static final class BooleanScorerCollector extends Collector {
private BucketTable bucketTable;
private int mask;
private Scorer scorer;
public BooleanScorerCollector(int mask, BucketTable bucketTable) {
this.mask = mask;
this.bucketTable = bucketTable;
}
public void setScorer(Scorer scorer) throws IOException {
this.scorer = scorer;
}
public final void collect(final int doc) throws IOException {
final BucketTable table = bucketTable;
final int i = doc & BucketTable.MASK;
Bucket bucket = table.buckets[i];
if (bucket == null)
table.buckets[i] = bucket = new Bucket();
if (bucket.doc != doc) { // invalid bucket
bucket.doc = doc; // set doc
bucket.score = scorer.score(); // initialize score
bucket.bits = mask; // initialize mask
bucket.coord = 1; // initialize coord
bucket.next = table.first; // push onto valid list
table.first = bucket;
} else { // valid bucket
bucket.score += scorer.score(); // increment score
bucket.bits |= mask; // add bits in mask
bucket.coord++; // increment coord
}
}
public void setNextReader(IndexReader reader, int docBase) {
// not needed by this implementation
}
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) {
throw new UnsupportedOperationException();
}
public Explanation explain(int doc) {
throw new UnsupportedOperationException();
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("boolean(");

View File

@ -20,7 +20,6 @@ package org.apache.lucene.search;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
/* See the description in BooleanScorer.java, comparing
* BooleanScorer & BooleanScorer2 */
@ -65,6 +64,7 @@ class BooleanScorer2 extends Scorer {
*/
private boolean allowDocsOutOfOrder;
private int doc = -1;
/** Create a BooleanScorer2.
* @param similarity The similarity to be used.
@ -151,7 +151,7 @@ class BooleanScorer2 extends Scorer {
this.scorer = scorer;
}
public float score() throws IOException {
int doc = doc();
int doc = docID();
if (doc >= lastScoredDoc) {
if (doc > lastScoredDoc) {
lastDocScore = scorer.score();
@ -161,14 +161,26 @@ class BooleanScorer2 extends Scorer {
}
return lastDocScore;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return scorer.doc();
}
public boolean next() throws IOException {
return scorer.next();
public int docID() {
return scorer.docID();
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return scorer.nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
return scorer.nextDoc();
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int docNr) throws IOException {
return scorer.skipTo(docNr);
return scorer.advance(docNr) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
return scorer.advance(target);
}
public Explanation explain(int docNr) throws IOException {
return scorer.explain(docNr);
@ -184,7 +196,7 @@ class BooleanScorer2 extends Scorer {
// once in score().
private float lastDocScore = Float.NaN;
public float score() throws IOException {
int doc = doc();
int doc = docID();
if (doc >= lastScoredDoc) {
if (doc > lastScoredDoc) {
lastDocScore = super.score();
@ -208,7 +220,7 @@ class BooleanScorer2 extends Scorer {
// once in score().
private float lastDocScore = Float.NaN;
public float score() throws IOException {
int doc = doc();
int doc = docID();
if (doc >= lastScoredDoc) {
if (doc > lastScoredDoc) {
lastDocScore = super.score();
@ -323,24 +335,16 @@ class BooleanScorer2 extends Scorer {
public void score(Collector collector) throws IOException {
if (allowDocsOutOfOrder && requiredScorers.size() == 0
&& prohibitedScorers.size() < 32) {
// fall back to BooleanScorer, scores documents somewhat out of order
BooleanScorer bs = new BooleanScorer(getSimilarity(), minNrShouldMatch);
Iterator si = optionalScorers.iterator();
while (si.hasNext()) {
bs.add((Scorer) si.next(), false /* required */, false /* prohibited */);
}
si = prohibitedScorers.iterator();
while (si.hasNext()) {
bs.add((Scorer) si.next(), false /* required */, true /* prohibited */);
}
bs.score(collector);
new BooleanScorer(getSimilarity(), minNrShouldMatch, optionalScorers,
prohibitedScorers).score(collector);
} else {
if (countingSumScorer == null) {
initCountingSumScorer();
}
collector.setScorer(this);
while (countingSumScorer.next()) {
collector.collect(countingSumScorer.doc());
int doc;
while ((doc = countingSumScorer.nextDoc()) != NO_MORE_DOCS) {
collector.collect(doc);
}
}
}
@ -355,60 +359,57 @@ class BooleanScorer2 extends Scorer {
* @deprecated use {@link #score(Collector, int)} instead.
*/
protected boolean score(HitCollector hc, int max) throws IOException {
return score(new HitCollectorWrapper(hc), max);
return score(new HitCollectorWrapper(hc), max, docID());
}
/** Expert: Collects matching documents in a range.
* <br>Note that {@link #next()} must be called once before this method is
* called for the first time.
* @param collector The collector to which all matching documents are passed through.
* @param max Do not score documents past this.
* @return true if more matching documents may remain.
*/
protected boolean score(Collector collector, int max) throws IOException {
protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
// null pointer exception when next() was not called before:
int docNr = countingSumScorer.doc();
int docNr = firstDocID;
collector.setScorer(this);
while (docNr < max) {
collector.collect(docNr);
if (!countingSumScorer.next()) {
return false;
}
docNr = countingSumScorer.doc();
docNr = countingSumScorer.nextDoc();
}
return true;
return docNr != NO_MORE_DOCS;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return countingSumScorer.doc(); }
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
if (countingSumScorer == null) {
initCountingSumScorer();
}
return countingSumScorer.next();
return doc = countingSumScorer.nextDoc();
}
public float score() throws IOException {
coordinator.nrMatchers = 0;
float sum = countingSumScorer.score();
return sum * coordinator.coordFactors[coordinator.nrMatchers];
}
/** Skips to the first match beyond the current whose document number is
* greater than or equal to a given target.
*
* <p>When this method is used the {@link #explain(int)} method should not be used.
*
* @param target The target document number.
* @return true iff there is such a match.
*/
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
if (countingSumScorer == null) {
initCountingSumScorer();
}
return countingSumScorer.skipTo(target);
return doc = countingSumScorer.advance(target);
}
/** Throws an UnsupportedOperationException.
* TODO: Implement an explanation of the coordination factor.
* @param doc The document number for the explanation.

View File

@ -24,76 +24,54 @@ import java.util.Comparator;
/** Scorer for conjunctions, sets of queries, all of which are required. */
class ConjunctionScorer extends Scorer {
private final Scorer[] scorers;
private boolean firstTime=true;
private boolean more;
private final float coord;
private int lastDoc=-1;
private int lastDoc = -1;
public ConjunctionScorer(Similarity similarity, Collection scorers) throws IOException {
this(similarity, (Scorer[])scorers.toArray(new Scorer[scorers.size()]));
this(similarity, (Scorer[]) scorers.toArray(new Scorer[scorers.size()]));
}
public ConjunctionScorer(Similarity similarity, Scorer[] scorers) throws IOException {
super(similarity);
this.scorers = scorers;
coord = getSimilarity().coord(this.scorers.length, this.scorers.length);
}
public int doc() { return lastDoc; }
public boolean next() throws IOException {
if (firstTime)
return init(0);
else if (more)
more = scorers[(scorers.length-1)].next();
return doNext();
}
private boolean doNext() throws IOException {
int first=0;
Scorer lastScorer = scorers[scorers.length-1];
Scorer firstScorer;
while (more && (firstScorer=scorers[first]).doc() < (lastDoc=lastScorer.doc())) {
more = firstScorer.skipTo(lastDoc);
lastScorer = firstScorer;
first = (first == (scorers.length-1)) ? 0 : first+1;
}
return more;
}
public boolean skipTo(int target) throws IOException {
if (firstTime)
return init(target);
else if (more)
more = scorers[(scorers.length-1)].skipTo(target);
return doNext();
}
// Note... most of this could be done in the constructor
// thus skipping a check for firstTime per call to next() and skipTo()
private boolean init(int target) throws IOException {
firstTime=false;
more = scorers.length>1;
for (int i=0; i<scorers.length; i++) {
more = target==0 ? scorers[i].next() : scorers[i].skipTo(target);
if (!more)
return false;
coord = similarity.coord(scorers.length, scorers.length);
for (int i = 0; i < scorers.length; i++) {
if (scorers[i].nextDoc() == NO_MORE_DOCS) {
// If even one of the sub-scorers does not have any documents, this
// scorer should not attempt to do any more work.
lastDoc = NO_MORE_DOCS;
return;
}
}
// Sort the array the first time...
// We don't need to sort the array in any future calls because we know
// it will already start off sorted (all scorers on same doc).
// note that this comparator is not consistent with equals!
Arrays.sort(scorers, new Comparator() { // sort the array
public int compare(Object o1, Object o2) {
return ((Scorer)o1).doc() - ((Scorer)o2).doc();
}
});
public int compare(Object o1, Object o2) {
return ((Scorer) o1).docID() - ((Scorer) o2).docID();
}
});
doNext();
// NOTE: doNext() must be called before the re-sorting of the array later on.
// The reason is this: assume there are 5 scorers, whose first docs are 1,
// 2, 3, 5, 5 respectively. Sorting (above) leaves the array as is. Calling
// doNext() here advances all the first scorers to 5 (or a larger doc ID
// they all agree on).
// However, if we re-sort before doNext() is called, the order will be 5, 3,
// 2, 1, 5 and then doNext() will stop immediately, since the first scorer's
// docs equals the last one. So the invariant that after calling doNext()
// all scorers are on the same doc ID is broken.
if (doNext() == NO_MORE_DOCS) {
// The scorers did not agree on any document.
lastDoc = NO_MORE_DOCS;
return;
}
// If first-time skip distance is any predictor of
// scorer sparseness, then we should always try to skip first on
@ -101,16 +79,62 @@ class ConjunctionScorer extends Scorer {
// Keep last scorer in it's last place (it will be the first
// to be skipped on), but reverse all of the others so that
// they will be skipped on in order of original high skip.
int end=(scorers.length-1);
for (int i=0; i<(end>>1); i++) {
int end = scorers.length - 1;
int max = end >> 1;
for (int i = 0; i < max; i++) {
Scorer tmp = scorers[i];
scorers[i] = scorers[end-i-1];
scorers[end-i-1] = tmp;
int idx = end - i - 1;
scorers[i] = scorers[idx];
scorers[idx] = tmp;
}
return more;
}
private int doNext() throws IOException {
int first = 0;
int doc = scorers[scorers.length - 1].docID();
Scorer firstScorer;
while ((firstScorer = scorers[first]).docID() < doc) {
doc = firstScorer.advance(doc);
first = first == scorers.length - 1 ? 0 : first + 1;
}
return doc;
}
public int advance(int target) throws IOException {
if (lastDoc == NO_MORE_DOCS) {
return lastDoc;
} else if (scorers[(scorers.length - 1)].docID() < target) {
scorers[(scorers.length - 1)].advance(target);
}
return lastDoc = doNext();
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return lastDoc; }
public int docID() {
return lastDoc;
}
public Explanation explain(int doc) {
throw new UnsupportedOperationException();
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
if (lastDoc == NO_MORE_DOCS) {
return lastDoc;
} else if (lastDoc == -1) {
return lastDoc = scorers[scorers.length - 1].docID();
}
scorers[(scorers.length - 1)].nextDoc();
return lastDoc = doNext();
}
public float score() throws IOException {
float sum = 0.0f;
for (int i = 0; i < scorers.length; i++) {
@ -119,8 +143,9 @@ class ConjunctionScorer extends Scorer {
return sum * coord;
}
public Explanation explain(int doc) {
throw new UnsupportedOperationException();
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
}

View File

@ -84,7 +84,7 @@ public class ConstantScoreQuery extends Query {
public Explanation explain(IndexReader reader, int doc) throws IOException {
ConstantScorer cs = (ConstantScorer)scorer(reader);
boolean exists = cs.docIdSetIterator.skipTo(doc) && (cs.docIdSetIterator.doc() == doc);
boolean exists = cs.docIdSetIterator.advance(doc) == doc;
ComplexExplanation result = new ComplexExplanation();
@ -108,7 +108,7 @@ public class ConstantScoreQuery extends Query {
protected class ConstantScorer extends Scorer {
final DocIdSetIterator docIdSetIterator;
final float theScore;
int doc=-1;
int doc = -1;
public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) throws IOException {
super(similarity);
@ -116,36 +116,48 @@ public class ConstantScoreQuery extends Query {
docIdSetIterator = filter.getDocIdSet(reader).iterator();
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return docIdSetIterator.next();
return docIdSetIterator.nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
return docIdSetIterator.nextDoc();
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return docIdSetIterator.doc();
}
public int docID() {
return docIdSetIterator.docID();
}
public float score() throws IOException {
return theScore;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return docIdSetIterator.skipTo(target);
return docIdSetIterator.advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
return docIdSetIterator.advance(target);
}
public Explanation explain(int doc) throws IOException {
throw new UnsupportedOperationException();
}
}
protected Weight createWeight(Searcher searcher) {
return new ConstantScoreQuery.ConstantWeight(searcher);
}
/** Prints a user-readable version of this query. */
public String toString(String field)
{
public String toString(String field) {
return "ConstantScore(" + filter.toString()
+ (getBoost()==1.0 ? ")" : "^" + getBoost());
}
@ -165,6 +177,3 @@ public class ConstantScoreQuery extends Query {
}
}

View File

@ -16,14 +16,14 @@ package org.apache.lucene.search;
* limitations under the License.
*/
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import org.apache.lucene.index.IndexReader;
/**
* A query that generates the union of documents produced by its subqueries, and that scores each document with the maximum
* score for that document as produced by any subquery, plus a tie breaking increment for any additional matching subqueries.
@ -124,13 +124,19 @@ public class DisjunctionMaxQuery extends Query {
/* Create the scorer used to score our associated DisjunctionMaxQuery */
public Scorer scorer(IndexReader reader) throws IOException {
DisjunctionMaxScorer result = new DisjunctionMaxScorer(tieBreakerMultiplier, similarity);
for (int i = 0 ; i < weights.size(); i++) {
Weight w = (Weight) weights.get(i);
Scorer[] scorers = new Scorer[weights.size()];
int idx = 0;
for (Iterator iter = weights.iterator(); iter.hasNext();) {
Weight w = (Weight) iter.next();
Scorer subScorer = w.scorer(reader);
if (subScorer == null) return null;
result.add(subScorer);
if (subScorer == null) {
return null;
} else if (subScorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
scorers[idx++] = subScorer;
}
}
if (idx == 0) return null; // all scorers did not have documents
DisjunctionMaxScorer result = new DisjunctionMaxScorer(tieBreakerMultiplier, similarity, scorers, idx);
return result;
}

View File

@ -17,7 +17,6 @@ package org.apache.lucene.search;
*/
import java.io.IOException;
import java.util.ArrayList;
/**
* The Scorer for DisjunctionMaxQuery's. The union of all documents generated by the the subquery scorers
@ -27,168 +26,192 @@ import java.util.ArrayList;
*/
class DisjunctionMaxScorer extends Scorer {
/* The scorers for subqueries that have remaining docs, kept as a min heap by number of next doc. */
private ArrayList subScorers = new ArrayList();
/* The scorers for subqueries that have remaining docs, kept as a min heap by number of next doc. */
private final Scorer[] subScorers;
private int numScorers;
/* Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result. */
private final float tieBreakerMultiplier;
private int doc = -1;
/* Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result. */
private float tieBreakerMultiplier;
/**
* Creates a new instance of DisjunctionMaxScorer
*
* @param tieBreakerMultiplier
* Multiplier applied to non-maximum-scoring subqueries for a
* document as they are summed into the result.
* @param similarity
* -- not used since our definition involves neither coord nor terms
* directly
* @param subScorers
* The sub scorers this Scorer should iterate on
* @param numScorers
* The actual number of scorers to iterate on. Note that the array's
* length may be larger than the actual number of scorers.
*/
public DisjunctionMaxScorer(float tieBreakerMultiplier,
Similarity similarity, Scorer[] subScorers, int numScorers) throws IOException {
super(similarity);
private boolean more = false; // True iff there is a next document
private boolean firstTime = true; // True iff next() has not yet been called
this.tieBreakerMultiplier = tieBreakerMultiplier;
// The passed subScorers array includes only scorers which have documents
// (DisjunctionMaxQuery takes care of that), and their nextDoc() was already
// called.
this.subScorers = subScorers;
this.numScorers = numScorers;
heapify();
}
/** Creates a new instance of DisjunctionMaxScorer
* @param tieBreakerMultiplier Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result.
* @param similarity -- not used since our definition involves neither coord nor terms directly */
public DisjunctionMaxScorer(float tieBreakerMultiplier, Similarity similarity) {
super(similarity);
this.tieBreakerMultiplier = tieBreakerMultiplier;
}
/**
* Generate the next document matching our associated DisjunctionMaxQuery.
*
* @return true iff there is a next document
* @deprecated use {@link #nextDoc()} instead.
*/
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
/** Add the scorer for a subquery
* @param scorer the scorer of a subquery of our associated DisjunctionMaxQuery
*/
public void add(Scorer scorer) throws IOException {
if (scorer.next()) { // Initialize and retain only if it produces docs
subScorers.add(scorer);
more = true;
public int nextDoc() throws IOException {
if (numScorers == 0) return doc = NO_MORE_DOCS;
while (subScorers[0].docID() == doc) {
if (subScorers[0].nextDoc() != NO_MORE_DOCS) {
heapAdjust(0);
} else {
heapRemoveRoot();
if (numScorers == 0) {
return doc = NO_MORE_DOCS;
}
}
}
return doc = subScorers[0].docID();
}
/** Generate the next document matching our associated DisjunctionMaxQuery.
* @return true iff there is a next document
*/
public boolean next() throws IOException {
if (!more) return false;
if (firstTime) {
heapify();
firstTime = false;
return true; // more would have been false if no subScorers had any docs
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return subScorers[0].doc();
}
public int docID() {
return doc;
}
/** Determine the current document score. Initially invalid, until {@link #next()} is called the first time.
* @return the score of the current generated document
*/
public float score() throws IOException {
int doc = subScorers[0].docID();
float[] sum = { subScorers[0].score() }, max = { sum[0] };
int size = numScorers;
scoreAll(1, size, doc, sum, max);
scoreAll(2, size, doc, sum, max);
return max[0] + (sum[0] - max[0]) * tieBreakerMultiplier;
}
// Recursively iterate all subScorers that generated last doc computing sum and max
private void scoreAll(int root, int size, int doc, float[] sum, float[] max) throws IOException {
if (root < size && subScorers[root].docID() == doc) {
float sub = subScorers[root].score();
sum[0] += sub;
max[0] = Math.max(max[0], sub);
scoreAll((root<<1)+1, size, doc, sum, max);
scoreAll((root<<1)+2, size, doc, sum, max);
}
}
/**
* Advance to the first document beyond the current whose number is greater
* than or equal to target.
*
* @param target
* the minimum number of the next desired document
* @return true iff there is a document to be generated whose number is at
* least target
* @deprecated use {@link #advance(int)} instead.
*/
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
if (numScorers == 0) return doc = NO_MORE_DOCS;
while (subScorers[0].docID() < target) {
if (subScorers[0].advance(target) != NO_MORE_DOCS) {
heapAdjust(0);
} else {
heapRemoveRoot();
if (numScorers == 0) {
return doc = NO_MORE_DOCS;
}
// Increment all generators that generated the last doc and adjust the heap.
int lastdoc = ((Scorer) subScorers.get(0)).doc();
do {
if (((Scorer) subScorers.get(0)).next())
heapAdjust(0);
else {
heapRemoveRoot();
if (subScorers.isEmpty()) return (more = false);
}
} while ( ((Scorer) subScorers.get(0)).doc()==lastdoc );
return true;
}
}
return doc = subScorers[0].docID();
}
/** Determine the current document number. Initially invalid, until {@link #next()} is called the first time.
* @return the document number of the currently generated document
*/
public int doc() {
return ((Scorer) subScorers.get(0)).doc();
/** Explain a score that we computed. UNSUPPORTED -- see explanation capability in DisjunctionMaxQuery.
* @param doc the number of a document we scored
* @return the Explanation for our score
*/
public Explanation explain(int doc) throws IOException {
throw new UnsupportedOperationException();
}
// Organize subScorers into a min heap with scorers generating the earliest document on top.
private void heapify() {
for (int i = (numScorers >> 1) - 1; i >= 0; i--) {
heapAdjust(i);
}
}
/** Determine the current document score. Initially invalid, until {@link #next()} is called the first time.
* @return the score of the current generated document
*/
public float score() throws IOException {
int doc = ((Scorer) subScorers.get(0)).doc();
float[] sum = {((Scorer) subScorers.get(0)).score()}, max = {sum[0]};
int size = subScorers.size();
scoreAll(1, size, doc, sum, max);
scoreAll(2, size, doc, sum, max);
return max[0] + (sum[0] - max[0])*tieBreakerMultiplier;
}
// Recursively iterate all subScorers that generated last doc computing sum and max
private void scoreAll(int root, int size, int doc, float[] sum, float[] max) throws IOException {
if (root<size && ((Scorer) subScorers.get(root)).doc() == doc) {
float sub = ((Scorer) subScorers.get(root)).score();
sum[0] += sub;
max[0] = Math.max(max[0], sub);
scoreAll((root<<1)+1, size, doc, sum, max);
scoreAll((root<<1)+2, size, doc, sum, max);
/* The subtree of subScorers at root is a min heap except possibly for its root element.
* Bubble the root down as required to make the subtree a heap.
*/
private void heapAdjust(int root) {
Scorer scorer = subScorers[root];
int doc = scorer.docID();
int i = root;
while (i <= (numScorers >> 1) - 1) {
int lchild = (i << 1) + 1;
Scorer lscorer = subScorers[lchild];
int ldoc = lscorer.docID();
int rdoc = Integer.MAX_VALUE, rchild = (i << 1) + 2;
Scorer rscorer = null;
if (rchild < numScorers) {
rscorer = subScorers[rchild];
rdoc = rscorer.docID();
}
if (ldoc < doc) {
if (rdoc < ldoc) {
subScorers[i] = rscorer;
subScorers[rchild] = scorer;
i = rchild;
} else {
subScorers[i] = lscorer;
subScorers[lchild] = scorer;
i = lchild;
}
} else if (rdoc < doc) {
subScorers[i] = rscorer;
subScorers[rchild] = scorer;
i = rchild;
} else {
return;
}
}
}
/** Advance to the first document beyond the current whose number is greater than or equal to target.
* @param target the minimum number of the next desired document
* @return true iff there is a document to be generated whose number is at least target
*/
public boolean skipTo(int target) throws IOException {
if (firstTime) {
if (!more) return false;
heapify();
firstTime = false;
}
while (subScorers.size()>0 && ((Scorer)subScorers.get(0)).doc()<target) {
if (((Scorer)subScorers.get(0)).skipTo(target))
heapAdjust(0);
else
heapRemoveRoot();
}
if ((subScorers.size()==0))
return (more = false);
return true;
}
/** Explain a score that we computed. UNSUPPORTED -- see explanation capability in DisjunctionMaxQuery.
* @param doc the number of a document we scored
* @return the Explanation for our score
*/
public Explanation explain(int doc) throws IOException {
throw new UnsupportedOperationException();
}
// Organize subScorers into a min heap with scorers generating the earlest document on top.
private void heapify() {
int size = subScorers.size();
for (int i=(size>>1)-1; i>=0; i--)
heapAdjust(i);
}
/* The subtree of subScorers at root is a min heap except possibly for its root element.
* Bubble the root down as required to make the subtree a heap.
*/
private void heapAdjust(int root) {
Scorer scorer=(Scorer)subScorers.get(root);
int doc=scorer.doc();
int i=root, size=subScorers.size();
while (i<=(size>>1)-1) {
int lchild=(i<<1)+1;
Scorer lscorer=(Scorer)subScorers.get(lchild);
int ldoc=lscorer.doc();
int rdoc=Integer.MAX_VALUE, rchild=(i<<1)+2;
Scorer rscorer=null;
if (rchild<size) {
rscorer=(Scorer)subScorers.get(rchild);
rdoc=rscorer.doc();
}
if (ldoc<doc) {
if (rdoc<ldoc) {
subScorers.set(i, rscorer);
subScorers.set(rchild, scorer);
i=rchild;
} else {
subScorers.set(i, lscorer);
subScorers.set(lchild, scorer);
i=lchild;
}
} else if (rdoc<doc) {
subScorers.set(i, rscorer);
subScorers.set(rchild, scorer);
i=rchild;
} else return;
}
}
// Remove the root Scorer from subScorers and re-establish it as a heap
private void heapRemoveRoot() {
int size=subScorers.size();
if (size==1)
subScorers.remove(0);
else {
subScorers.set(0, subScorers.get(size-1));
subScorers.remove(size-1);
heapAdjust(0);
}
// Remove the root Scorer from subScorers and re-establish it as a heap
private void heapRemoveRoot() {
if (numScorers == 1) {
subScorers[0] = null;
numScorers = 0;
} else {
subScorers[0] = subScorers[numScorers - 1];
subScorers[numScorers - 1] = null;
--numScorers;
heapAdjust(0);
}
}
}

View File

@ -102,7 +102,7 @@ class DisjunctionSumScorer extends Scorer {
scorerDocQueue = new ScorerDocQueue(nrScorers);
while (si.hasNext()) {
Scorer se = (Scorer) si.next();
if (se.next()) { // doc() method will be used in scorerDocQueue.
if (se.nextDoc() != NO_MORE_DOCS) { // doc() method will be used in scorerDocQueue.
scorerDocQueue.insert(se);
}
}
@ -124,7 +124,7 @@ class DisjunctionSumScorer extends Scorer {
*/
public void score(Collector collector) throws IOException {
collector.setScorer(this);
while (next()) {
while (nextDoc() != NO_MORE_DOCS) {
collector.collect(currentDoc);
}
}
@ -139,7 +139,7 @@ class DisjunctionSumScorer extends Scorer {
* @deprecated use {@link #score(Collector, int)} instead.
*/
protected boolean score(HitCollector hc, int max) throws IOException {
return score(new HitCollectorWrapper(hc), max);
return score(new HitCollectorWrapper(hc), max, docID());
}
/** Expert: Collects matching documents in a range. Hook for optimization.
@ -149,22 +149,29 @@ class DisjunctionSumScorer extends Scorer {
* @param max Do not score documents past this.
* @return true if more matching documents may remain.
*/
protected boolean score(Collector collector, int max) throws IOException {
protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
// firstDocID is ignored since nextDoc() sets 'currentDoc'
collector.setScorer(this);
while (currentDoc < max) {
collector.collect(currentDoc);
if (!next()) {
if (nextDoc() == NO_MORE_DOCS) {
return false;
}
}
return true;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return (scorerDocQueue.size() >= minimumNrMatchers)
&& advanceAfterCurrent();
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
if (scorerDocQueue.size() < minimumNrMatchers || !advanceAfterCurrent()) {
currentDoc = NO_MORE_DOCS;
}
return currentDoc;
}
/** Advance all subscorers after the current document determined by the
* top of the <code>scorerDocQueue</code>.
@ -176,7 +183,7 @@ class DisjunctionSumScorer extends Scorer {
* <br>In case there is a match, </code>currentDoc</code>, </code>currentSumScore</code>,
* and </code>nrMatchers</code> describe the match.
*
* @todo Investigate whether it is possible to use skipTo() when
* TODO: Investigate whether it is possible to use skipTo() when
* the minimum number of matchers is bigger than one, ie. try and use the
* character of ConjunctionScorer for the minimum number of matchers.
* Also delay calling score() on the sub scorers until the minimum number of
@ -190,7 +197,7 @@ class DisjunctionSumScorer extends Scorer {
currentScore = scorerDocQueue.topScore();
nrMatchers = 1;
do { // Until all subscorers are after currentDoc
if (! scorerDocQueue.topNextAndAdjustElsePop()) {
if (!scorerDocQueue.topNextAndAdjustElsePop()) {
if (scorerDocQueue.size() == 0) {
break; // nothing more to advance, check for last match.
}
@ -215,8 +222,13 @@ class DisjunctionSumScorer extends Scorer {
*/
public float score() throws IOException { return currentScore; }
/** @deprecated use {@link #docID()} instead. */
public int doc() { return currentDoc; }
public int docID() {
return currentDoc;
}
/** Returns the number of subscorers matching the current document.
* Initially invalid, until {@link #next()} is called the first time.
*/
@ -224,31 +236,52 @@ class DisjunctionSumScorer extends Scorer {
return nrMatchers;
}
/** Skips to the first match beyond the current whose document number is
* greater than or equal to a given target.
* <br>When this method is used the {@link #explain(int)} method should not be used.
* <br>The implementation uses the skipTo() method on the subscorers.
* @param target The target document number.
/**
* Skips to the first match beyond the current whose document number is
* greater than or equal to a given target. <br>
* When this method is used the {@link #explain(int)} method should not be
* used. <br>
* The implementation uses the skipTo() method on the subscorers.
*
* @param target
* The target document number.
* @return true iff there is such a match.
* @deprecated use {@link #advance(int)} instead.
*/
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
/**
* Advances to the first match beyond the current whose document number is
* greater than or equal to a given target. <br>
* When this method is used the {@link #explain(int)} method should not be
* used. <br>
* The implementation uses the skipTo() method on the subscorers.
*
* @param target
* The target document number.
* @return the document whose number is greater than or equal to the given
* target, or -1 if none exist.
*/
public int advance(int target) throws IOException {
if (scorerDocQueue.size() < minimumNrMatchers) {
return false;
return currentDoc = NO_MORE_DOCS;
}
if (target <= currentDoc) {
return true;
return currentDoc;
}
do {
if (scorerDocQueue.topDoc() >= target) {
return advanceAfterCurrent();
} else if (! scorerDocQueue.topSkipToAndAdjustElsePop(target)) {
return advanceAfterCurrent() ? currentDoc : (currentDoc = NO_MORE_DOCS);
} else if (!scorerDocQueue.topSkipToAndAdjustElsePop(target)) {
if (scorerDocQueue.size() < minimumNrMatchers) {
return false;
return currentDoc = NO_MORE_DOCS;
}
}
} while (true);
}
/** @return An explanation for the score of a given document. */
public Explanation explain(int doc) throws IOException {
Explanation res = new Explanation();

View File

@ -20,30 +20,130 @@ package org.apache.lucene.search;
import java.io.IOException;
/**
* This abstract class defines methods to iterate over a set of
* non-decreasing doc ids.
* This abstract class defines methods to iterate over a set of non-decreasing
* doc ids. Note that this class assumes it iterates on doc Ids, and therefore
* {@link #NO_MORE_DOCS} is set to {@value #NO_MORE_DOCS} in order to be used as
* a sentinel object. Implementations of this class are expected to consider
* {@link Integer#MAX_VALUE} as an invalid value.
*/
public abstract class DocIdSetIterator {
/** Returns the current document number. <p> This is invalid until {@link
#next()} is called for the first time.*/
public abstract int doc();
/** Moves to the next docId in the set. Returns true, iff
* there is such a docId. */
public abstract boolean next() throws IOException;
/** Skips entries to the first beyond the current whose document number is
* greater than or equal to <i>target</i>. <p>Returns true iff there is such
* an entry. <p>Behaves as if written: <pre>
* boolean skipTo(int target) {
* do {
* if (!next())
* return false;
* } while (target > doc());
* return true;
* }
* </pre>
* Some implementations are considerably more efficient than that.
*/
public abstract boolean skipTo(int target) throws IOException;
// TODO (3.0): review the javadocs and remove any references to '3.0'.
private int doc = -1;
/**
* When returned by {@link #nextDoc()}, {@link #advance(int)} and
* {@link #doc()} it means there are no more docs in the iterator.
*/
public static final int NO_MORE_DOCS = Integer.MAX_VALUE;
/**
* Unsupported anymore. Call {@link #docID()} instead. This method throws
* {@link UnsupportedOperationException} if called.
*
* @deprecated use {@link #docID()} instead.
*/
public int doc() {
throw new UnsupportedOperationException("Call docID() instead.");
}
/**
* Returns the following:
* <ul>
* <li>-1 or {@link #NO_MORE_DOCS} if {@link #nextDoc()} or
* {@link #advance(int)} were not called yet.
* <li>{@link #NO_MORE_DOCS} if the iterator has exhausted.
* <li>Otherwise it should return the doc ID it is currently on.
* </ul>
* <p>
* <b>NOTE:</b> in 3.0, this method will become abstract.
*
* @since 2.9
*/
public int docID() {
return doc;
}
/**
* Unsupported anymore. Call {@link #nextDoc()} instead. This method throws
* {@link UnsupportedOperationException} if called.
*
* @deprecated use {@link #nextDoc()} instead. This will be removed in 3.0
*/
public boolean next() throws IOException {
throw new UnsupportedOperationException("Call nextDoc() instead.");
}
/**
* Unsupported anymore. Call {@link #advance(int)} instead. This method throws
* {@link UnsupportedOperationException} if called.
*
* @deprecated use {@link #advance(int)} instead. This will be removed in 3.0
*/
public boolean skipTo(int target) throws IOException {
throw new UnsupportedOperationException("Call advance() instead.");
}
/**
* Advances to the next document in the set and returns the doc it is
* currently on, or {@link #NO_MORE_DOCS} if there are no more docs in the
* set.<br>
*
* <b>NOTE:</b> in 3.0 this method will become abstract, following the removal
* of {@link #next()}. For backward compatibility it is implemented as:
*
* <pre>
* public int nextDoc() throws IOException {
* return next() ? doc() : NO_MORE_DOCS;
* }
* </pre>
*
* <b>NOTE:</b> after the iterator has exhausted you should not call this
* method, as it may result in unpredicted behavior.
*
* @since 2.9
*/
public int nextDoc() throws IOException {
return doc = next() ? doc() : NO_MORE_DOCS;
}
/**
* Advances to the first beyond the current whose document number is greater
* than or equal to <i>target</i>. Returns the current document number or
* {@link #NO_MORE_DOCS} if there are no more docs in the set.
* <p>
* Behaves as if written:
*
* <pre>
* int advance(int target) {
* int doc;
* while ((doc = nextDoc()) &lt; target) {
* }
* return doc;
* }
* </pre>
*
* Some implementations are considerably more efficient than that.
* <p>
* <b>NOTE:</b> certain implemenations may return a different value (each
* time) if called several times in a row with the same target.
* <p>
* <b>NOTE:</b> this method may be called with {@value #NO_MORE_DOCS} for
* efficiency by some Scorers. If your implementation cannot efficiently
* determine that it should exhaust, it is recommended that you check for that
* value in each call to this method.
* <p>
* <b>NOTE:</b> after the iterator has exhausted you should not call this
* method, as it may result in unpredicted behavior.
* <p>
* <b>NOTE:</b> in 3.0 this method will become abstract, following the removal
* of {@link #skipTo(int)}.
*
* @since 2.9
*/
public int advance(int target) throws IOException {
while (nextDoc() < target) {}
return doc;
}
}

View File

@ -158,37 +158,51 @@ public class FieldCacheRangeFilter extends Filter {
protected class RangeMultiFilterIterator extends DocIdSetIterator {
private int doc = -1;
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return doc;
}
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() {
try {
do {
doc++;
} while (fcsi.order[doc] > inclusiveUpperPoint
|| fcsi.order[doc] < inclusiveLowerPoint);
return true;
} catch (ArrayIndexOutOfBoundsException e) {
doc = Integer.MAX_VALUE;
return false;
doc = NO_MORE_DOCS;
}
return doc;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) {
try {
doc = target;
while (fcsi.order[doc] > inclusiveUpperPoint
|| fcsi.order[doc] < inclusiveLowerPoint) {
doc++;
}
return true;
} catch (ArrayIndexOutOfBoundsException e) {
doc = Integer.MAX_VALUE;
return false;
doc = NO_MORE_DOCS;
}
return doc;
}
}
}
}

View File

@ -17,12 +17,11 @@ package org.apache.lucene.search;
* limitations under the License.
*/
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.TermDocs; // for javadoc
import org.apache.lucene.util.OpenBitSet;
import java.io.IOException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.OpenBitSet;
/**
* A {@link Filter} that only accepts documents whose single
* term value in the specified field is contained in the
@ -133,33 +132,44 @@ public class FieldCacheTermsFilter extends Filter {
protected class FieldCacheTermsFilterDocIdSetIterator extends DocIdSetIterator {
private int doc = -1;
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return doc;
}
public boolean next() {
try {
do {
doc++;
} while (!openBitSet.fastGet(fcsi.order[doc]));
return true;
} catch (ArrayIndexOutOfBoundsException e) {
doc = Integer.MAX_VALUE;
return false;
}
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() {
try {
while (!openBitSet.fastGet(fcsi.order[++doc])) {}
} catch (ArrayIndexOutOfBoundsException e) {
doc = NO_MORE_DOCS;
}
return doc;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) {
try {
doc = target;
while (!openBitSet.fastGet(fcsi.order[doc])) {
doc++;
}
return true;
} catch (ArrayIndexOutOfBoundsException e) {
doc = Integer.MAX_VALUE;
return false;
doc = NO_MORE_DOCS;
}
return doc;
}
}
}

View File

@ -25,10 +25,9 @@ import java.io.IOException;
* mechanism on an underlying DocIdSetIterator. See {@link
* FilteredDocIdSet}.
*/
public abstract class FilteredDocIdSetIterator extends DocIdSetIterator {
protected DocIdSetIterator _innerIter;
private int _currentDoc;
private int doc;
/**
* Constructor.
@ -39,7 +38,7 @@ public abstract class FilteredDocIdSetIterator extends DocIdSetIterator {
throw new IllegalArgumentException("null iterator");
}
_innerIter = innerIter;
_currentDoc = -1;
doc = -1;
}
/**
@ -50,42 +49,49 @@ public abstract class FilteredDocIdSetIterator extends DocIdSetIterator {
*/
abstract protected boolean match(int doc);
// @Override
/** @deprecated use {@link #docID()} instead. */
public final int doc() {
return _currentDoc;
return doc;
}
// @Override
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public final boolean next() throws IOException{
while (_innerIter.next()) {
int doc = _innerIter.doc();
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
while ((doc = _innerIter.nextDoc()) != NO_MORE_DOCS) {
if (match(doc)) {
_currentDoc = doc;
return true;
return doc;
}
}
return false;
return doc;
}
// @Override
/** @deprecated use {@link #advance(int)} instead. */
public final boolean skipTo(int n) throws IOException{
boolean flag = _innerIter.skipTo(n);
if (flag) {
int doc = _innerIter.doc();
return advance(n) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
doc = _innerIter.advance(target);
if (doc != NO_MORE_DOCS) {
if (match(doc)) {
_currentDoc = doc;
return true;
return doc;
} else {
while (_innerIter.next()) {
int docid = _innerIter.doc();
if (match(docid)) {
_currentDoc = docid;
return true;
while ((doc = _innerIter.nextDoc()) != NO_MORE_DOCS) {
if (match(doc)) {
return doc;
}
}
return false;
return doc;
}
}
return flag;
return doc;
}
}

View File

@ -85,7 +85,7 @@ extends Query {
}
Filter f = FilteredQuery.this.filter;
DocIdSetIterator docIdSetIterator = f.getDocIdSet(ir).iterator();
if (docIdSetIterator.skipTo(i) && (docIdSetIterator.doc() == i)) {
if (docIdSetIterator.advance(i) == i) {
return inner;
} else {
Explanation result = new Explanation
@ -99,35 +99,51 @@ extends Query {
public Query getQuery() { return FilteredQuery.this; }
// return a filtering scorer
public Scorer scorer (IndexReader indexReader) throws IOException {
public Scorer scorer (IndexReader indexReader) throws IOException {
final Scorer scorer = weight.scorer(indexReader);
final DocIdSetIterator docIdSetIterator = filter.getDocIdSet(indexReader).iterator();
return new Scorer(similarity) {
private boolean advanceToCommon() throws IOException {
while (scorer.doc() != docIdSetIterator.doc()) {
if (scorer.doc() < docIdSetIterator.doc()) {
if (!scorer.skipTo(docIdSetIterator.doc())) {
return false;
}
} else if (!docIdSetIterator.skipTo(scorer.doc())) {
return false;
private int doc = -1;
private int advanceToCommon(int scorerDoc, int disiDoc) throws IOException {
while (scorerDoc != disiDoc) {
if (scorerDoc < disiDoc) {
scorerDoc = scorer.advance(disiDoc);
} else {
disiDoc = docIdSetIterator.advance(scorerDoc);
}
}
return true;
return scorerDoc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return docIdSetIterator.next() && scorer.next() && advanceToCommon();
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
int scorerDoc, disiDoc;
return doc = (disiDoc = docIdSetIterator.nextDoc()) != NO_MORE_DOCS
&& (scorerDoc = scorer.nextDoc()) != NO_MORE_DOCS
&& advanceToCommon(scorerDoc, disiDoc) != NO_MORE_DOCS ? scorer.docID() : NO_MORE_DOCS;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return scorer.doc(); }
public int docID() { return doc; }
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int i) throws IOException {
return docIdSetIterator.skipTo(i)
&& scorer.skipTo(docIdSetIterator.doc())
&& advanceToCommon();
return advance(i) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
int disiDoc, scorerDoc;
return doc = (disiDoc = docIdSetIterator.advance(target)) != NO_MORE_DOCS
&& (scorerDoc = scorer.advance(disiDoc)) != NO_MORE_DOCS
&& advanceToCommon(scorerDoc, disiDoc) != NO_MORE_DOCS ? scorer.docID() : NO_MORE_DOCS;
}
public float score() throws IOException { return getBoost() * scorer.score(); }
@ -136,7 +152,7 @@ extends Query {
public Explanation explain (int i) throws IOException {
Explanation exp = scorer.explain(i);
if (docIdSetIterator.skipTo(i) && (docIdSetIterator.doc() == i)) {
if (docIdSetIterator.advance(i) == i) {
exp.setDescription ("allowed by filter: "+exp.getDescription());
exp.setValue(getBoost() * exp.getValue());
} else {

View File

@ -258,28 +258,34 @@ public class IndexSearcher extends Searcher {
if (scorer == null)
return;
int docID = scorer.docID();
assert docID == -1 || docID == DocIdSetIterator.NO_MORE_DOCS;
if (filter == null) {
scorer.score(collector);
return;
}
DocIdSetIterator filterDocIdIterator = filter.getDocIdSet(reader).iterator(); // CHECKME: use ConjunctionScorer here?
// CHECKME: use ConjunctionScorer here?
DocIdSetIterator filterIter = filter.getDocIdSet(reader).iterator();
int filterDoc = filterIter.nextDoc();
int scorerDoc = scorer.advance(filterDoc);
boolean more = filterDocIdIterator.next() && scorer.skipTo(filterDocIdIterator.doc());
collector.setScorer(scorer);
while (more) {
int filterDocId = filterDocIdIterator.doc();
if (filterDocId > scorer.doc() && !scorer.skipTo(filterDocId)) {
more = false;
} else {
int scorerDocId = scorer.doc();
if (scorerDocId == filterDocId) { // permitted by filter
collector.collect(scorerDocId);
more = filterDocIdIterator.next();
} else {
more = filterDocIdIterator.skipTo(scorerDocId);
while (true) {
if (scorerDoc == filterDoc) {
// Check if scorer has exhausted, only before collecting.
if (scorerDoc == DocIdSetIterator.NO_MORE_DOCS) {
break;
}
collector.collect(scorerDoc);
filterDoc = filterIter.nextDoc();
scorerDoc = scorer.advance(filterDoc);
} else if (scorerDoc > filterDoc) {
filterDoc = filterIter.advance(scorerDoc);
} else {
scorerDoc = scorer.advance(filterDoc);
}
}
}

View File

@ -47,9 +47,10 @@ public class MatchAllDocsQuery extends Query {
final TermDocs termDocs;
final float score;
final byte[] norms;
MatchAllScorer(IndexReader reader, Similarity similarity, Weight w, byte[] norms) throws IOException
{
private int doc = -1;
MatchAllScorer(IndexReader reader, Similarity similarity, Weight w,
byte[] norms) throws IOException {
super(similarity);
this.termDocs = reader.termDocs(null);
score = w.getValue();
@ -60,26 +61,36 @@ public class MatchAllDocsQuery extends Query {
return null; // not called... see MatchAllDocsWeight.explain()
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return termDocs.doc();
}
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return termDocs.next();
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
return doc = termDocs.next() ? termDocs.doc() : NO_MORE_DOCS;
}
public float score() {
if (norms == null) {
return score;
} else {
return score * Similarity.decodeNorm(norms[doc()]); // normalize for field
}
return norms == null ? score : score * Similarity.decodeNorm(norms[docID()]);
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return termDocs.skipTo(target);
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
return doc = termDocs.skipTo(target) ? termDocs.doc() : NO_MORE_DOCS;
}
}
private class MatchAllDocsWeight implements Weight {

View File

@ -23,13 +23,22 @@ import java.io.IOException;
class NonMatchingScorer extends Scorer {
public NonMatchingScorer() { super(null); } // no similarity used
/** @deprecated use {@link #docID()} instead. */
public int doc() { throw new UnsupportedOperationException(); }
public int docID() { return NO_MORE_DOCS; }
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException { return false; }
public int nextDoc() throws IOException { return NO_MORE_DOCS; }
public float score() { throw new UnsupportedOperationException(); }
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) { return false; }
public int advance(int target) { return NO_MORE_DOCS; }
public Explanation explain(int doc) {
Explanation e = new Explanation();

View File

@ -43,9 +43,8 @@ abstract class PhraseScorer extends Scorer {
private float freq; //prhase frequency in current doc as computed by phraseFreq().
PhraseScorer(Weight weight, TermPositions[] tps, int[] offsets, Similarity similarity,
byte[] norms) {
PhraseScorer(Weight weight, TermPositions[] tps, int[] offsets,
Similarity similarity, byte[] norms) {
super(similarity);
this.norms = norms;
this.weight = weight;
@ -60,25 +59,37 @@ abstract class PhraseScorer extends Scorer {
PhrasePositions pp = new PhrasePositions(tps[i], offsets[i]);
if (last != null) { // add next to end of list
last.next = pp;
} else
} else {
first = pp;
}
last = pp;
}
pq = new PhraseQueue(tps.length); // construct empty pq
first.doc = -1;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return first.doc; }
public int docID() { return first.doc; }
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
if (firstTime) {
init();
firstTime = false;
} else if (more) {
more = last.next(); // trigger further scanning
}
return doNext();
if (!doNext()) {
first.doc = NO_MORE_DOCS;
}
return first.doc;
}
// next without initial increment
@ -107,16 +118,25 @@ abstract class PhraseScorer extends Scorer {
return norms == null ? raw : raw * Similarity.decodeNorm(norms[first.doc]); // normalize
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
firstTime = false;
for (PhrasePositions pp = first; more && pp != null; pp = pp.next) {
more = pp.skipTo(target);
}
if (more)
if (more) {
sort(); // re-sort
return doNext();
}
if (!doNext()) {
first.doc = NO_MORE_DOCS;
}
return first.doc;
}
/**
* For a document containing all the phrase query terms, compute the
* frequency of the phrase in that document.
@ -127,16 +147,19 @@ abstract class PhraseScorer extends Scorer {
protected abstract float phraseFreq() throws IOException;
private void init() throws IOException {
for (PhrasePositions pp = first; more && pp != null; pp = pp.next)
for (PhrasePositions pp = first; more && pp != null; pp = pp.next) {
more = pp.next();
if(more)
}
if (more) {
sort();
}
}
private void sort() {
pq.clear();
for (PhrasePositions pp = first; pp != null; pp = pp.next)
pq.put(pp);
for (PhrasePositions pp = first; pp != null; pp = pp.next) {
pq.add(pp);
}
pqToList();
}
@ -163,9 +186,8 @@ abstract class PhraseScorer extends Scorer {
public Explanation explain(final int doc) throws IOException {
Explanation tfExplanation = new Explanation();
while (next() && doc() < doc) {}
float phraseFreq = (doc() == doc) ? freq : 0.0f;
int d = advance(doc);
float phraseFreq = (d == doc) ? freq : 0.0f;
tfExplanation.setValue(getSimilarity().tf(phraseFreq));
tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");

View File

@ -29,76 +29,78 @@ import java.io.IOException;
class ReqExclScorer extends Scorer {
private Scorer reqScorer;
private DocIdSetIterator exclDisi;
private int doc = -1;
/** Construct a <code>ReqExclScorer</code>.
* @param reqScorer The scorer that must match, except where
* @param exclDisi indicates exclusion.
*/
public ReqExclScorer(
Scorer reqScorer,
DocIdSetIterator exclDisi) {
public ReqExclScorer(Scorer reqScorer, DocIdSetIterator exclDisi) {
super(null); // No similarity used.
this.reqScorer = reqScorer;
this.exclDisi = exclDisi;
}
private boolean firstTime = true;
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
if (firstTime) {
if (! exclDisi.next()) {
exclDisi = null; // exhausted at start
}
firstTime = false;
}
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
if (reqScorer == null) {
return false;
return doc;
}
if (! reqScorer.next()) {
doc = reqScorer.nextDoc();
if (doc == NO_MORE_DOCS) {
reqScorer = null; // exhausted, nothing left
return false;
return doc;
}
if (exclDisi == null) {
return true; // reqScorer.next() already returned true
return doc;
}
return toNonExcluded();
return doc = toNonExcluded();
}
/** Advance to non excluded doc.
* <br>On entry:
* <ul>
* <li>reqScorer != null,
* <li>exclDisi != null,
* <li>exclScorer != null,
* <li>reqScorer was advanced once via next() or skipTo()
* and reqScorer.doc() may still be excluded.
* </ul>
* Advances reqScorer a non excluded required doc, if any.
* @return true iff there is a non excluded required doc.
*/
private boolean toNonExcluded() throws IOException {
int exclDoc = exclDisi.doc();
private int toNonExcluded() throws IOException {
int exclDoc = exclDisi.docID();
int reqDoc = reqScorer.docID(); // may be excluded
do {
int reqDoc = reqScorer.doc(); // may be excluded
if (reqDoc < exclDoc) {
return true; // reqScorer advanced to before exclScorer, ie. not excluded
return reqDoc; // reqScorer advanced to before exclScorer, ie. not excluded
} else if (reqDoc > exclDoc) {
if (! exclDisi.skipTo(reqDoc)) {
exclDoc = exclDisi.advance(reqDoc);
if (exclDoc == NO_MORE_DOCS) {
exclDisi = null; // exhausted, no more exclusions
return true;
return reqDoc;
}
exclDoc = exclDisi.doc();
if (exclDoc > reqDoc) {
return true; // not excluded
return reqDoc; // not excluded
}
}
} while (reqScorer.next());
} while ((reqDoc = reqScorer.nextDoc()) != NO_MORE_DOCS);
reqScorer = null; // exhausted, nothing left
return false;
return NO_MORE_DOCS;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return reqScorer.doc(); // reqScorer may be null when next() or skipTo() already return false
}
public int docID() {
return doc;
}
/** Returns the score of the current document matching the query.
* Initially invalid, until {@link #next()} is called the first time.
@ -108,35 +110,28 @@ class ReqExclScorer extends Scorer {
return reqScorer.score(); // reqScorer may be null when next() or skipTo() already return false
}
/** Skips to the first match beyond the current whose document number is
* greater than or equal to a given target.
* <br>When this method is used the {@link #explain(int)} method should not be used.
* @param target The target document number.
* @return true iff there is such a match.
*/
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
if (firstTime) {
firstTime = false;
if (! exclDisi.skipTo(target)) {
exclDisi = null; // exhausted
}
}
if (reqScorer == null) {
return false;
}
if (exclDisi == null) {
return reqScorer.skipTo(target);
}
if (! reqScorer.skipTo(target)) {
reqScorer = null;
return false;
}
return toNonExcluded();
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
if (reqScorer == null) {
return doc = NO_MORE_DOCS;
}
if (exclDisi == null) {
return doc = reqScorer.advance(target);
}
if (reqScorer.advance(target) == NO_MORE_DOCS) {
reqScorer = null;
return doc = NO_MORE_DOCS;
}
return doc = toNonExcluded();
}
public Explanation explain(int doc) throws IOException {
Explanation res = new Explanation();
if (exclDisi.skipTo(doc) && (exclDisi.doc() == doc)) {
if (exclDisi.advance(doc) == doc) {
res.setDescription("excluded");
} else {
res.setDescription("not excluded");

View File

@ -43,44 +43,52 @@ class ReqOptSumScorer extends Scorer {
this.optScorer = optScorer;
}
private boolean firstTimeOptScorer = true;
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return reqScorer.next();
}
public int nextDoc() throws IOException {
return reqScorer.nextDoc();
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return reqScorer.skipTo(target);
}
public int advance(int target) throws IOException {
return reqScorer.advance(target);
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return reqScorer.doc();
}
public int docID() {
return reqScorer.docID();
}
/** Returns the score of the current document matching the query.
* Initially invalid, until {@link #next()} is called the first time.
* @return The score of the required scorer, eventually increased by the score
* of the optional scorer when it also matches the current document.
*/
public float score() throws IOException {
int curDoc = reqScorer.doc();
int curDoc = reqScorer.docID();
float reqScore = reqScorer.score();
if (firstTimeOptScorer) {
firstTimeOptScorer = false;
if (! optScorer.skipTo(curDoc)) {
optScorer = null;
return reqScore;
}
} else if (optScorer == null) {
if (optScorer == null) {
return reqScore;
} else if ((optScorer.doc() < curDoc) && (! optScorer.skipTo(curDoc))) {
}
int optScorerDoc = optScorer.docID();
if (optScorerDoc < curDoc && (optScorerDoc = optScorer.advance(curDoc)) == NO_MORE_DOCS) {
optScorer = null;
return reqScore;
}
// assert (optScorer != null) && (optScorer.doc() >= curDoc);
return (optScorer.doc() == curDoc)
? reqScore + optScorer.score()
: reqScore;
return optScorerDoc == curDoc ? reqScore + optScorer.score() : reqScore;
}
/** Explain the score of a document.

View File

@ -42,8 +42,8 @@ public class ScoreCachingWrappingScorer extends Scorer {
this.scorer = scorer;
}
protected boolean score(Collector collector, int max) throws IOException {
return scorer.score(collector, max);
protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
return scorer.score(collector, max, firstDocID);
}
public Similarity getSimilarity() {
@ -55,7 +55,7 @@ public class ScoreCachingWrappingScorer extends Scorer {
}
public float score() throws IOException {
int doc = scorer.doc();
int doc = scorer.docID();
if (doc != curDoc) {
curScore = scorer.score();
curDoc = doc;
@ -64,20 +64,35 @@ public class ScoreCachingWrappingScorer extends Scorer {
return curScore;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return scorer.doc();
}
public int docID() {
return scorer.docID();
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return scorer.next();
}
public int nextDoc() throws IOException {
return scorer.nextDoc();
}
public void score(Collector collector) throws IOException {
scorer.score(collector);
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return scorer.skipTo(target);
}
public int advance(int target) throws IOException {
return scorer.advance(target);
}
}

View File

@ -71,8 +71,9 @@ public abstract class Scorer extends DocIdSetIterator {
*/
public void score(Collector collector) throws IOException {
collector.setScorer(this);
while (next()) {
collector.collect(doc());
int doc;
while ((doc = nextDoc()) != NO_MORE_DOCS) {
collector.collect(doc);
}
}
@ -86,26 +87,33 @@ public abstract class Scorer extends DocIdSetIterator {
* @deprecated use {@link #score(Collector, int)} instead.
*/
protected boolean score(HitCollector hc, int max) throws IOException {
return score(new HitCollectorWrapper(hc), max);
return score(new HitCollectorWrapper(hc), max, docID());
}
/** Expert: Collects matching documents in a range. Hook for optimization.
* Note that {@link #next()} must be called once before this method is called
* for the first time.
* @param collector The collector to which all matching documents are passed.
* @param max Do not score documents past this.
/**
* Expert: Collects matching documents in a range. Hook for optimization.
* Note, <code>firstDocID</code> is added to ensure that {@link #nextDoc()}
* was called before this method.
*
* @param collector
* The collector to which all matching documents are passed.
* @param max
* Do not score documents past this.
* @param firstDocID
* The first document ID (ensures {@link #nextDoc()} is called before
* this method.
* @return true if more matching documents may remain.
*/
protected boolean score(Collector collector, int max) throws IOException {
protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
collector.setScorer(this);
while (doc() < max) {
collector.collect(doc());
if (!next())
return false;
int doc = firstDocID;
while (doc < max) {
collector.collect(doc);
doc = nextDoc();
}
return true;
return doc == NO_MORE_DOCS;
}
/** Returns the score of the current document matching the query.
* Initially invalid, until {@link #next()} or {@link #skipTo(int)}
* is called the first time, or when called from within

View File

@ -31,7 +31,7 @@ final class TermScorer extends Scorer {
private TermDocs termDocs;
private byte[] norms;
private float weightValue;
private int doc;
private int doc = -1;
private final int[] docs = new int[32]; // buffered doc numbers
private final int[] freqs = new int[32]; // buffered term freqs
@ -65,16 +65,16 @@ final class TermScorer extends Scorer {
}
public void score(Collector c) throws IOException {
next();
score(c, Integer.MAX_VALUE);
score(c, Integer.MAX_VALUE, nextDoc());
}
/** @deprecated use {@link #score(Collector, int)} instead. */
protected boolean score(HitCollector c, int end) throws IOException {
return score(new HitCollectorWrapper(c), end);
return score(new HitCollectorWrapper(c), end, doc);
}
protected boolean score(Collector c, int end) throws IOException {
// firstDocID is ignored since nextDoc() sets 'doc'
protected boolean score(Collector c, int end, int firstDocID) throws IOException {
c.setScorer(this);
while (doc < end) { // for docs in window
c.collect(doc); // collect score
@ -94,17 +94,31 @@ final class TermScorer extends Scorer {
return true;
}
/** Returns the current document number matching the query.
* Initially invalid, until {@link #next()} is called the first time.
*/
/** @deprecated use {@link #docID()} instead. */
public int doc() { return doc; }
public int docID() { return doc; }
/** Advances to the next document matching the query.
* <br>The iterator over the matching documents is buffered using
/**
* Advances to the next document matching the query. <br>
* The iterator over the matching documents is buffered using
* {@link TermDocs#read(int[],int[])}.
*
* @return true iff there is another document matching the query.
* @deprecated use {@link #nextDoc()} instead.
*/
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
/**
* Advances to the next document matching the query. <br>
* The iterator over the matching documents is buffered using
* {@link TermDocs#read(int[],int[])}.
*
* @return the document matching the query or -1 if there are no more documents.
*/
public int nextDoc() throws IOException {
pointer++;
if (pointer >= pointerMax) {
pointerMax = termDocs.read(docs, freqs); // refill buffer
@ -112,15 +126,15 @@ final class TermScorer extends Scorer {
pointer = 0;
} else {
termDocs.close(); // close stream
doc = Integer.MAX_VALUE; // set to sentinel value
return false;
return doc = NO_MORE_DOCS;
}
}
doc = docs[pointer];
return true;
return doc;
}
public float score() {
assert doc != -1;
int f = freqs[pointer];
float raw = // compute tf(f)*weight
f < SCORE_CACHE_SIZE // check cache
@ -130,18 +144,34 @@ final class TermScorer extends Scorer {
return norms == null ? raw : raw * SIM_NORM_DECODER[norms[doc] & 0xFF]; // normalize for field
}
/** Skips to the first match beyond the current whose document number is
* greater than or equal to a given target.
* <br>The implementation uses {@link TermDocs#skipTo(int)}.
* @param target The target document number.
/**
* Skips to the first match beyond the current whose document number is
* greater than or equal to a given target. <br>
* The implementation uses {@link TermDocs#skipTo(int)}.
*
* @param target
* The target document number.
* @return true iff there is such a match.
* @deprecated use {@link #advance(int)} instead.
*/
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
/**
* Advances to the first match beyond the current whose document number is
* greater than or equal to a given target. <br>
* The implementation uses {@link TermDocs#skipTo(int)}.
*
* @param target
* The target document number.
* @return the matching document or -1 if none exist.
*/
public int advance(int target) throws IOException {
// first scan in cache
for (pointer++; pointer < pointerMax; pointer++) {
if (docs[pointer] >= target) {
doc = docs[pointer];
return true;
return doc = docs[pointer];
}
}
@ -153,11 +183,11 @@ final class TermScorer extends Scorer {
docs[pointer] = doc = termDocs.doc();
freqs[pointer] = termDocs.freq();
} else {
doc = Integer.MAX_VALUE;
doc = NO_MORE_DOCS;
}
return result;
return doc;
}
/** Returns an explanation of the score for a document.
* <br>When this method is used, the {@link #next()} method
* and the {@link #score(HitCollector)} method should not be used.

View File

@ -367,41 +367,53 @@ public class CustomScoreQuery extends Query {
this.vScores = new float[valSrcScorers.length];
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#next() */
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
boolean hasNext = subQueryScorer.next();
if (hasNext) {
for(int i = 0; i < valSrcScorers.length; i++) {
valSrcScorers[i].skipTo(subQueryScorer.doc());
}
}
return hasNext;
return nextDoc() != NO_MORE_DOCS;
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#doc() */
public int nextDoc() throws IOException {
int doc = subQueryScorer.nextDoc();
if (doc != NO_MORE_DOCS) {
for (int i = 0; i < valSrcScorers.length; i++) {
valSrcScorers[i].advance(doc);
}
}
return doc;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return subQueryScorer.doc();
}
public int docID() {
return subQueryScorer.docID();
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#score() */
public float score() throws IOException {
for(int i = 0; i < valSrcScorers.length; i++) {
for (int i = 0; i < valSrcScorers.length; i++) {
vScores[i] = valSrcScorers[i].score();
}
return qWeight * customScore(subQueryScorer.doc(), subQueryScorer.score(), vScores);
return qWeight * customScore(subQueryScorer.docID(), subQueryScorer.score(), vScores);
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#skipTo(int) */
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
boolean hasNext = subQueryScorer.skipTo(target);
if (hasNext) {
for (int i = 0; i < valSrcScorers.length; i++) {
valSrcScorers[i].skipTo(subQueryScorer.doc());
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
int doc = subQueryScorer.advance(target);
if (doc != NO_MORE_DOCS) {
for (int i = 0; i < valSrcScorers.length; i++) {
valSrcScorers[i].advance(doc);
}
}
return hasNext;
return doc;
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#explain(int) */
public Explanation explain(int doc) throws IOException {
Explanation subQueryExpl = weight.subQueryWeight.explain(reader,doc);

View File

@ -115,6 +115,7 @@ public class ValueSourceQuery extends Query {
private final float qWeight;
private final DocValues vals;
private final TermDocs termDocs;
private int doc = -1;
// constructor
private ValueSourceScorer(Similarity similarity, IndexReader reader, ValueSourceWeight w) throws IOException {
@ -126,26 +127,37 @@ public class ValueSourceQuery extends Query {
termDocs = reader.termDocs(null);
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#next() */
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return termDocs.next();
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#doc()
*/
public int nextDoc() throws IOException {
return doc = termDocs.next() ? termDocs.doc() : NO_MORE_DOCS;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return termDocs.doc();
}
public int docID() {
return doc;
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#score() */
public float score() throws IOException {
return qWeight * vals.floatVal(termDocs.doc());
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#skipTo(int) */
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return termDocs.skipTo(target);
}
public int advance(int target) throws IOException {
return doc = termDocs.skipTo(target) ? termDocs.doc() : NO_MORE_DOCS;
}
/*(non-Javadoc) @see org.apache.lucene.search.Scorer#explain(int) */
public Explanation explain(int doc) throws IOException {

View File

@ -33,6 +33,7 @@ public class SpanScorer extends Scorer {
protected byte[] norms;
protected float value;
/** @deprecated not needed anymore */
protected boolean firstTime = true;
protected boolean more = true;
@ -46,33 +47,46 @@ public class SpanScorer extends Scorer {
this.norms = norms;
this.weight = weight;
this.value = weight.getValue();
doc = -1;
if (this.spans.next()) {
doc = -1;
} else {
doc = NO_MORE_DOCS;
more = false;
}
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
if (firstTime) {
more = spans.next();
firstTime = false;
}
return setFreqCurrentDoc();
return nextDoc() != NO_MORE_DOCS;
}
public boolean skipTo(int target) throws IOException {
if (firstTime) {
more = spans.skipTo(target);
firstTime = false;
public int nextDoc() throws IOException {
if (!setFreqCurrentDoc()) {
doc = NO_MORE_DOCS;
}
if (! more) {
return false;
return doc;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
if (!more) {
return doc = NO_MORE_DOCS;
}
if (spans.doc() < target) { // setFreqCurrentDoc() leaves spans.doc() ahead
more = spans.skipTo(target);
}
return setFreqCurrentDoc();
if (!setFreqCurrentDoc()) {
doc = NO_MORE_DOCS;
}
return doc;
}
protected boolean setFreqCurrentDoc() throws IOException {
if (! more) {
if (!more) {
return false;
}
doc = spans.doc();
@ -85,7 +99,10 @@ public class SpanScorer extends Scorer {
return true;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return doc; }
public int docID() { return doc; }
public float score() throws IOException {
float raw = getSimilarity().tf(freq) * value; // raw score
@ -95,9 +112,9 @@ public class SpanScorer extends Scorer {
public Explanation explain(final int doc) throws IOException {
Explanation tfExplanation = new Explanation();
skipTo(doc);
int expDoc = advance(doc);
float phraseFreq = (doc() == doc) ? freq : 0.0f;
float phraseFreq = (expDoc == doc) ? freq : 0.0f;
tfExplanation.setValue(getSimilarity().tf(phraseFreq));
tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");

View File

@ -18,6 +18,7 @@ package org.apache.lucene.util;
*/
import java.util.BitSet;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
@ -50,28 +51,40 @@ public class DocIdBitSet extends DocIdSet {
this.docId = -1;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
assert docId != -1;
return docId;
}
public int docID() {
return docId;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() {
// (docId + 1) on next line requires -1 initial value for docNr:
return checkNextDocId(bitSet.nextSetBit(docId + 1));
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() {
// (docId + 1) on next line requires -1 initial value for docNr:
int d = bitSet.nextSetBit(docId + 1);
// -1 returned by BitSet.nextSetBit() when exhausted
docId = d == -1 ? NO_MORE_DOCS : d;
return docId;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int skipDocNr) {
return checkNextDocId( bitSet.nextSetBit(skipDocNr));
return advance(skipDocNr) != NO_MORE_DOCS;
}
private boolean checkNextDocId(int d) {
if (d == -1) { // -1 returned by BitSet.nextSetBit() when exhausted
docId = Integer.MAX_VALUE;
return false;
} else {
docId = d;
return true;
}
public int advance(int target) {
int d = bitSet.nextSetBit(target);
// -1 returned by BitSet.nextSetBit() when exhausted
docId = d == -1 ? NO_MORE_DOCS : d;
return docId;
}
}
}

View File

@ -47,8 +47,10 @@ public class OpenBitSetDISI extends OpenBitSet {
* constructor.
*/
public void inPlaceOr(DocIdSetIterator disi) throws IOException {
while (disi.next() && (disi.doc() < size())) {
fastSet(disi.doc());
int doc;
long size = size();
while ((doc = disi.nextDoc()) < size) {
fastSet(doc);
}
}
@ -60,8 +62,8 @@ public class OpenBitSetDISI extends OpenBitSet {
*/
public void inPlaceAnd(DocIdSetIterator disi) throws IOException {
int bitSetDoc = nextSetBit(0);
while ((bitSetDoc != -1) && disi.skipTo(bitSetDoc)) {
int disiDoc = disi.doc();
int disiDoc;
while (bitSetDoc != -1 && (disiDoc = disi.advance(bitSetDoc)) != DocIdSetIterator.NO_MORE_DOCS) {
clear(bitSetDoc, disiDoc);
bitSetDoc = nextSetBit(disiDoc + 1);
}
@ -77,8 +79,10 @@ public class OpenBitSetDISI extends OpenBitSet {
* constructor.
*/
public void inPlaceNot(DocIdSetIterator disi) throws IOException {
while (disi.next() && (disi.doc() < size())) {
fastClear(disi.doc());
int doc;
long size = size();
while ((doc = disi.nextDoc()) < size) {
fastClear(doc);
}
}
@ -89,8 +93,10 @@ public class OpenBitSetDISI extends OpenBitSet {
* constructor.
*/
public void inPlaceXor(DocIdSetIterator disi) throws IOException {
while (disi.next() && (disi.doc() < size())) {
fastFlip(disi.doc());
int doc;
long size = size();
while ((doc = disi.nextDoc()) < size) {
fastFlip(doc);
}
}
}

View File

@ -17,8 +17,6 @@
package org.apache.lucene.util;
import java.io.IOException;
import org.apache.lucene.search.DocIdSetIterator;
/** An iterator to iterate over set bits in an OpenBitSet.
@ -35,7 +33,34 @@ public class OpenBitSetIterator extends DocIdSetIterator {
// should be faster than accessing an array for each index, and
// the total array size is kept smaller (256*sizeof(int))=1K
protected final static int[] bitlist={
0x0,0x1,0x2,0x21,0x3,0x31,0x32,0x321,0x4,0x41,0x42,0x421,0x43,0x431,0x432,0x4321,0x5,0x51,0x52,0x521,0x53,0x531,0x532,0x5321,0x54,0x541,0x542,0x5421,0x543,0x5431,0x5432,0x54321,0x6,0x61,0x62,0x621,0x63,0x631,0x632,0x6321,0x64,0x641,0x642,0x6421,0x643,0x6431,0x6432,0x64321,0x65,0x651,0x652,0x6521,0x653,0x6531,0x6532,0x65321,0x654,0x6541,0x6542,0x65421,0x6543,0x65431,0x65432,0x654321,0x7,0x71,0x72,0x721,0x73,0x731,0x732,0x7321,0x74,0x741,0x742,0x7421,0x743,0x7431,0x7432,0x74321,0x75,0x751,0x752,0x7521,0x753,0x7531,0x7532,0x75321,0x754,0x7541,0x7542,0x75421,0x7543,0x75431,0x75432,0x754321,0x76,0x761,0x762,0x7621,0x763,0x7631,0x7632,0x76321,0x764,0x7641,0x7642,0x76421,0x7643,0x76431,0x76432,0x764321,0x765,0x7651,0x7652,0x76521,0x7653,0x76531,0x76532,0x765321,0x7654,0x76541,0x76542,0x765421,0x76543,0x765431,0x765432,0x7654321,0x8,0x81,0x82,0x821,0x83,0x831,0x832,0x8321,0x84,0x841,0x842,0x8421,0x843,0x8431,0x8432,0x84321,0x85,0x851,0x852,0x8521,0x853,0x8531,0x8532,0x85321,0x854,0x8541,0x8542,0x85421,0x8543,0x85431,0x85432,0x854321,0x86,0x861,0x862,0x8621,0x863,0x8631,0x8632,0x86321,0x864,0x8641,0x8642,0x86421,0x8643,0x86431,0x86432,0x864321,0x865,0x8651,0x8652,0x86521,0x8653,0x86531,0x86532,0x865321,0x8654,0x86541,0x86542,0x865421,0x86543,0x865431,0x865432,0x8654321,0x87,0x871,0x872,0x8721,0x873,0x8731,0x8732,0x87321,0x874,0x8741,0x8742,0x87421,0x8743,0x87431,0x87432,0x874321,0x875,0x8751,0x8752,0x87521,0x8753,0x87531,0x87532,0x875321,0x8754,0x87541,0x87542,0x875421,0x87543,0x875431,0x875432,0x8754321,0x876,0x8761,0x8762,0x87621,0x8763,0x87631,0x87632,0x876321,0x8764,0x87641,0x87642,0x876421,0x87643,0x876431,0x876432,0x8764321,0x8765,0x87651,0x87652,0x876521,0x87653,0x876531,0x876532,0x8765321,0x87654,0x876541,0x876542,0x8765421,0x876543,0x8765431,0x8765432,0x87654321
0x0, 0x1, 0x2, 0x21, 0x3, 0x31, 0x32, 0x321, 0x4, 0x41, 0x42, 0x421, 0x43,
0x431, 0x432, 0x4321, 0x5, 0x51, 0x52, 0x521, 0x53, 0x531, 0x532, 0x5321,
0x54, 0x541, 0x542, 0x5421, 0x543, 0x5431, 0x5432, 0x54321, 0x6, 0x61, 0x62,
0x621, 0x63, 0x631, 0x632, 0x6321, 0x64, 0x641, 0x642, 0x6421, 0x643,
0x6431, 0x6432, 0x64321, 0x65, 0x651, 0x652, 0x6521, 0x653, 0x6531, 0x6532,
0x65321, 0x654, 0x6541, 0x6542, 0x65421, 0x6543, 0x65431, 0x65432, 0x654321,
0x7, 0x71, 0x72, 0x721, 0x73, 0x731, 0x732, 0x7321, 0x74, 0x741, 0x742,
0x7421, 0x743, 0x7431, 0x7432, 0x74321, 0x75, 0x751, 0x752, 0x7521, 0x753,
0x7531, 0x7532, 0x75321, 0x754, 0x7541, 0x7542, 0x75421, 0x7543, 0x75431,
0x75432, 0x754321, 0x76, 0x761, 0x762, 0x7621, 0x763, 0x7631, 0x7632,
0x76321, 0x764, 0x7641, 0x7642, 0x76421, 0x7643, 0x76431, 0x76432, 0x764321,
0x765, 0x7651, 0x7652, 0x76521, 0x7653, 0x76531, 0x76532, 0x765321, 0x7654,
0x76541, 0x76542, 0x765421, 0x76543, 0x765431, 0x765432, 0x7654321, 0x8,
0x81, 0x82, 0x821, 0x83, 0x831, 0x832, 0x8321, 0x84, 0x841, 0x842, 0x8421,
0x843, 0x8431, 0x8432, 0x84321, 0x85, 0x851, 0x852, 0x8521, 0x853, 0x8531,
0x8532, 0x85321, 0x854, 0x8541, 0x8542, 0x85421, 0x8543, 0x85431, 0x85432,
0x854321, 0x86, 0x861, 0x862, 0x8621, 0x863, 0x8631, 0x8632, 0x86321, 0x864,
0x8641, 0x8642, 0x86421, 0x8643, 0x86431, 0x86432, 0x864321, 0x865, 0x8651,
0x8652, 0x86521, 0x8653, 0x86531, 0x86532, 0x865321, 0x8654, 0x86541,
0x86542, 0x865421, 0x86543, 0x865431, 0x865432, 0x8654321, 0x87, 0x871,
0x872, 0x8721, 0x873, 0x8731, 0x8732, 0x87321, 0x874, 0x8741, 0x8742,
0x87421, 0x8743, 0x87431, 0x87432, 0x874321, 0x875, 0x8751, 0x8752, 0x87521,
0x8753, 0x87531, 0x87532, 0x875321, 0x8754, 0x87541, 0x87542, 0x875421,
0x87543, 0x875431, 0x875432, 0x8754321, 0x876, 0x8761, 0x8762, 0x87621,
0x8763, 0x87631, 0x87632, 0x876321, 0x8764, 0x87641, 0x87642, 0x876421,
0x87643, 0x876431, 0x876432, 0x8764321, 0x8765, 0x87651, 0x87652, 0x876521,
0x87653, 0x876531, 0x876532, 0x8765321, 0x87654, 0x876541, 0x876542,
0x8765421, 0x876543, 0x8765431, 0x8765432, 0x87654321
};
/***** the python code that generated bitlist
def bits2int(val):
@ -56,14 +81,13 @@ public class OpenBitSetIterator extends DocIdSetIterator {
// for efficiency, or have a common root interface? (or
// maybe both? could ask for a SetBitsIterator, etc...
private final long[] arr;
private final int words;
private int i=-1;
private long word;
private int wordShift;
private int indexArray;
private int curDocId;
private int curDocId = -1;
public OpenBitSetIterator(OpenBitSet obs) {
this(obs.getBits(), obs.getNumWords());
@ -104,50 +128,24 @@ public class OpenBitSetIterator extends DocIdSetIterator {
}
******/
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() {
if (indexArray==0) {
if (word!=0) {
word >>>= 8;
wordShift += 8;
}
while (word==0) {
if (++i >= words) {
curDocId = -1;
return false;
}
word = arr[i];
wordShift =-1; // loop invariant code motion should move this
}
// after the first time, should I go with a linear search, or
// stick with the binary search in shift?
shift();
}
int bitIndex = (indexArray & 0x0f) + wordShift;
indexArray >>>= 4;
// should i<<6 be cached as a separate variable?
// it would only save one cycle in the best circumstances.
curDocId = (i<<6) + bitIndex;
return true;
return nextDoc() != NO_MORE_DOCS;
}
/** Moves iterator to the next doc and returns its id;
returns -1 when this iterator is exhausted. */
public int nextDoc() {
if (indexArray==0) {
if (word!=0) {
if (indexArray == 0) {
if (word != 0) {
word >>>= 8;
wordShift += 8;
}
while (word==0) {
while (word == 0) {
if (++i >= words) {
return curDocId = -1;
return curDocId = NO_MORE_DOCS;
}
word = arr[i];
wordShift =-1; // loop invariant code motion should move this
wordShift = -1; // loop invariant code motion should move this
}
// after the first time, should I go with a linear search, or
@ -162,60 +160,30 @@ public class OpenBitSetIterator extends DocIdSetIterator {
return curDocId = (i<<6) + bitIndex;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) {
indexArray=0;
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) {
indexArray = 0;
i = target >> 6;
if (i>=words) {
word =0; // setup so next() will also return -1
curDocId = -1;
return false;
if (i >= words) {
word = 0; // setup so next() will also return -1
return curDocId = NO_MORE_DOCS;
}
wordShift = target & 0x3f;
word = arr[i] >>> wordShift;
if (word !=0) {
if (word != 0) {
wordShift--; // compensate for 1 based arrIndex
} else {
while (word ==0) {
while (word == 0) {
if (++i >= words) {
curDocId = -1;
return false;
return curDocId = NO_MORE_DOCS;
}
word = arr[i];
}
wordShift =-1;
}
shift();
int bitIndex = (indexArray & 0x0f) + wordShift;
indexArray >>>= 4;
// should i<<6 be cached as a separate variable?
// it would only save one cycle in the best circumstances.
curDocId = (i<<6) + bitIndex;
return true;
}
/** Behaves like {@link #skipTo(int)} and returns the docId the iterator
* skipped to; returns -1 if no valid document could be skipped to. */
public int next(int fromIndex) {
indexArray=0;
i = fromIndex >> 6;
if (i>=words) {
word =0; // setup so next() will also return -1
return curDocId = -1;
}
wordShift = fromIndex & 0x3f;
word = arr[i] >>> wordShift;
if (word !=0) {
wordShift--; // compensate for 1 based arrIndex
} else {
while (word ==0) {
if (++i >= words) {
return curDocId = -1;
}
word = arr[i];
}
wordShift =-1;
wordShift = -1;
}
shift();
@ -226,9 +194,14 @@ public class OpenBitSetIterator extends DocIdSetIterator {
// it would only save one cycle in the best circumstances.
return curDocId = (i<<6) + bitIndex;
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return this.curDocId;
return curDocId;
}
public int docID() {
return curDocId;
}
}

View File

@ -20,6 +20,8 @@ package org.apache.lucene.util;
/* Derived from org.apache.lucene.util.PriorityQueue of March 2005 */
import java.io.IOException;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Scorer;
/** A ScorerDocQueue maintains a partial ordering of its Scorers such that the
@ -35,14 +37,14 @@ public class ScorerDocQueue { // later: SpansQueue for spans with doc and term
Scorer scorer;
int doc;
HeapedScorerDoc(Scorer s) { this(s, s.doc()); }
HeapedScorerDoc(Scorer s) { this(s, s.docID()); }
HeapedScorerDoc(Scorer scorer, int doc) {
this.scorer = scorer;
this.doc = doc;
}
void adjust() { doc = scorer.doc(); }
void adjust() { doc = scorer.docID(); }
}
private HeapedScorerDoc topHSD; // same as heap[1], only for speed
@ -79,7 +81,7 @@ public class ScorerDocQueue { // later: SpansQueue for spans with doc and term
put(scorer);
return true;
} else {
int docNr = scorer.doc();
int docNr = scorer.docID();
if ((size > 0) && (! (docNr < topHSD.doc))) { // heap[1] is top()
heap[1] = new HeapedScorerDoc(scorer, docNr);
downHeap();
@ -113,16 +115,16 @@ public class ScorerDocQueue { // later: SpansQueue for spans with doc and term
}
public final boolean topNextAndAdjustElsePop() throws IOException {
return checkAdjustElsePop( topHSD.scorer.next());
return checkAdjustElsePop(topHSD.scorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
}
public final boolean topSkipToAndAdjustElsePop(int target) throws IOException {
return checkAdjustElsePop( topHSD.scorer.skipTo(target));
return checkAdjustElsePop(topHSD.scorer.advance(target) != DocIdSetIterator.NO_MORE_DOCS);
}
private boolean checkAdjustElsePop(boolean cond) {
if (cond) { // see also adjustTop
topHSD.doc = topHSD.scorer.doc();
topHSD.doc = topHSD.scorer.docID();
} else { // see also popNoResult
heap[1] = heap[size]; // move last to first
heap[size] = null;

View File

@ -24,10 +24,15 @@ import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
/**
* Store and iterate sorted integers in compressed form in RAM.
* <br>The code for compressing the differences between ascending integers was
* borrowed from {@link org.apache.lucene.store.IndexInput} and
* {@link org.apache.lucene.store.IndexOutput}.
* Stores and iterate on sorted integers in compressed form in RAM. <br>
* The code for compressing the differences between ascending integers was
* borrowed from {@link org.apache.lucene.store.IndexInput} and
* {@link org.apache.lucene.store.IndexOutput}.
* <p>
* <b>NOTE:</b> this class assumes the stored integers are doc Ids (hence why it
* extends {@link DocIdSet}). Therefore its {@link #iterator()} assumes {@value
* DocIdSetIterator#NO_MORE_DOCS} can be used as sentinel. If you intent to use
* this value, then make sure it's not used during search flow.
*/
public class SortedVIntList extends DocIdSet {
/** When a BitSet has fewer than 1 in BITS2VINTLIST_SIZE bits set,
@ -99,8 +104,9 @@ public class SortedVIntList extends DocIdSet {
*/
public SortedVIntList(DocIdSetIterator docIdSetIterator) throws IOException {
SortedVIntListBuilder builder = new SortedVIntListBuilder();
while (docIdSetIterator.next()) {
builder.addInt(docIdSetIterator.doc());
int doc;
while ((doc = docIdSetIterator.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
builder.addInt(doc);
}
builder.done();
}
@ -181,6 +187,7 @@ public class SortedVIntList extends DocIdSet {
return new DocIdSetIterator() {
int bytePos = 0;
int lastInt = 0;
int doc = -1;
private void advance() {
// See org.apache.lucene.store.IndexInput.readVInt()
@ -192,26 +199,43 @@ public class SortedVIntList extends DocIdSet {
}
}
/** @deprecated use {@link #docID()} instead. */
public int doc() {return lastInt;}
public int docID() {
return doc;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() {
if (bytePos >= lastBytePos) {
return false;
} else {
advance();
return true;
}
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() {
if (bytePos >= lastBytePos) {
doc = NO_MORE_DOCS;
} else {
advance();
doc = lastInt;
}
return doc;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int docNr) {
return advance(docNr) != NO_MORE_DOCS;
}
public int advance(int target) {
while (bytePos < lastBytePos) {
advance();
if (lastInt >= docNr) { // No skipping to docNr available.
return true;
if (lastInt >= target) {
return doc = lastInt;
}
}
return false;
return doc = NO_MORE_DOCS;
}
};
}
}

View File

@ -175,18 +175,32 @@ final class JustCompileSearch {
static final class JustCompileDocIdSetIterator extends DocIdSetIterator {
/** @deprecated delete in 3.0 */
public int doc() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int docID() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
/** @deprecated delete in 3.0 */
public boolean next() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
/** @deprecated delete in 3.0 */
public boolean skipTo(int target) throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int nextDoc() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int advance(int target) throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileFieldCache implements FieldCache {
@ -470,6 +484,11 @@ final class JustCompileSearch {
super(similarity);
}
protected boolean score(Collector collector, int max, int firstDocID)
throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public Explanation explain(int doc) throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@ -478,18 +497,32 @@ final class JustCompileSearch {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
/** @deprecated delete in 3.0 */
public int doc() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int docID() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
/** @deprecated delete in 3.0. */
public boolean next() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
/** @deprecated delete in 3.0. */
public boolean skipTo(int target) throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int nextDoc() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
public int advance(int target) throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileSimilarity extends Similarity {

View File

@ -1,13 +1,13 @@
package org.apache.lucene.search;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import junit.framework.Assert;
import org.apache.lucene.index.IndexReader;
/**
@ -56,17 +56,17 @@ public class QueryUtils {
}
public static void checkEqual(Query q1, Query q2) {
TestCase.assertEquals(q1, q2);
TestCase.assertEquals(q1.hashCode(), q2.hashCode());
Assert.assertEquals(q1, q2);
Assert.assertEquals(q1.hashCode(), q2.hashCode());
}
public static void checkUnequal(Query q1, Query q2) {
TestCase.assertTrue(!q1.equals(q2));
TestCase.assertTrue(!q2.equals(q1));
Assert.assertTrue(!q1.equals(q2));
Assert.assertTrue(!q2.equals(q1));
// possible this test can fail on a hash collision... if that
// happens, please change test to use a different example.
TestCase.assertTrue(q1.hashCode() != q2.hashCode());
Assert.assertTrue(q1.hashCode() != q2.hashCode());
}
/** deep check that explanations of a query 'score' correctly */
@ -169,8 +169,9 @@ public class QueryUtils {
try {
int op = order[(opidx[0]++)%order.length];
//System.out.println(op==skip_op ? "skip("+(sdoc[0]+1)+")":"next()");
boolean more = op==skip_op ? scorer.skipTo(sdoc[0]+1) : scorer.next();
sdoc[0] = scorer.doc();
boolean more = op == skip_op ? scorer.advance(sdoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS
: scorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS;
sdoc[0] = scorer.docID();
float scorerScore = scorer.score();
float scorerScore2 = scorer.score();
float scoreDiff = Math.abs(score-scorerScore);
@ -204,8 +205,9 @@ public class QueryUtils {
// make sure next call to scorer is false.
int op = order[(opidx[0]++)%order.length];
//System.out.println(op==skip_op ? "last: skip()":"last: next()");
boolean more = op==skip_op ? scorer.skipTo(sdoc[0]+1) : scorer.next();
TestCase.assertFalse(more);
boolean more = (op == skip_op ? scorer.advance(sdoc[0] + 1) : scorer
.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS;
Assert.assertFalse(more);
}
}
@ -228,11 +230,11 @@ public class QueryUtils {
for (int i=lastDoc[0]+1; i<=doc; i++) {
Weight w = q.weight(s);
Scorer scorer = w.scorer(s.getIndexReader());
TestCase.assertTrue("query collected "+doc+" but skipTo("+i+") says no more docs!",scorer.skipTo(i));
TestCase.assertEquals("query collected "+doc+" but skipTo("+i+") got to "+scorer.doc(),doc,scorer.doc());
Assert.assertTrue("query collected "+doc+" but skipTo("+i+") says no more docs!",scorer.advance(i) != DocIdSetIterator.NO_MORE_DOCS);
Assert.assertEquals("query collected "+doc+" but skipTo("+i+") got to "+scorer.docID(),doc,scorer.docID());
float skipToScore = scorer.score();
TestCase.assertEquals("unstable skipTo("+i+") score!",skipToScore,scorer.score(),maxDiff);
TestCase.assertEquals("query assigned doc "+doc+" a score of <"+score+"> but skipTo("+i+") has <"+skipToScore+">!",score,skipToScore,maxDiff);
Assert.assertEquals("unstable skipTo("+i+") score!",skipToScore,scorer.score(),maxDiff);
Assert.assertEquals("query assigned doc "+doc+" a score of <"+score+"> but skipTo("+i+") has <"+skipToScore+">!",score,skipToScore,maxDiff);
}
lastDoc[0] = doc;
} catch (IOException e) {
@ -245,8 +247,8 @@ public class QueryUtils {
});
Weight w = q.weight(s);
Scorer scorer = w.scorer(s.getIndexReader());
boolean more = scorer.skipTo(lastDoc[0]+1);
boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS;
if (more)
TestCase.assertFalse("query's last doc was "+lastDoc[0]+" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.doc(),more);
Assert.assertFalse("query's last doc was "+lastDoc[0]+" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more);
}
}

View File

@ -18,23 +18,18 @@ package org.apache.lucene.search;
*/
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import java.util.Random;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
import java.util.Random;
/** Test BooleanQuery2 against BooleanQuery by overriding the standard query parser.
* This also tests the scoring order of BooleanQuery.
*/
@ -158,13 +153,14 @@ public class TestBoolean2 extends LuceneTestCase {
int tot=0;
BooleanQuery q1 = null;
try {
// increase number of iterations for more complete testing
for (int i=0; i<1000; i++) {
int level = rnd.nextInt(3);
BooleanQuery q1 = randBoolQuery(new Random(rnd.nextLong()), level, field, vals, null);
q1 = randBoolQuery(new Random(rnd.nextLong()), level, field, vals, null);
// Can't sort by relevance since floating point numbers may not quite
// match up.
Sort sort = Sort.INDEXORDER;
@ -181,6 +177,10 @@ public class TestBoolean2 extends LuceneTestCase {
CheckHits.checkEqual(q1, hits1, hits2);
}
} catch (Exception e) {
// For easier debugging
System.out.println("failed query: " + q1);
throw e;
} finally { // even when a test fails.
BooleanQuery.setAllowDocsOutOfOrder(false);
}

View File

@ -18,6 +18,7 @@ package org.apache.lucene.search;
*/
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
@ -74,5 +75,41 @@ public class TestBooleanScorer extends LuceneTestCase
}
public void testEmptyBucketWithMoreDocs() throws Exception {
// This test checks the logic of nextDoc() when all sub scorers have docs
// beyond the first bucket (for example). Currently, the code relies on the
// 'more' variable to work properly, and this test ensures that if the logic
// changes, we have a test to back it up.
Similarity sim = Similarity.getDefault();
Scorer[] scorers = new Scorer[] {new Scorer(sim) {
private int doc = -1;
public Explanation explain(int doc) throws IOException { return null; }
public float score() throws IOException { return 0; }
/** @deprecated delete in 3.0. */
public int doc() { return 3000; }
public int docID() { return doc; }
/** @deprecated delete in 3.0 */
public boolean next() throws IOException { return nextDoc() != NO_MORE_DOCS; }
public int nextDoc() throws IOException {
return doc = doc == -1 ? 3000 : NO_MORE_DOCS;
}
/** @deprecated delete in 3.0 */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
return doc = target <= 3000 ? 3000 : NO_MORE_DOCS;
}
}};
BooleanScorer bs = new BooleanScorer(sim, 1, Arrays.asList(scorers), null);
assertEquals("should have received 3000", 3000, bs.nextDoc());
assertEquals("should have received NO_MORE_DOCS", DocIdSetIterator.NO_MORE_DOCS, bs.nextDoc());
}
}

View File

@ -136,10 +136,9 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase{
final Weight dw = dq.weight(s);
final Scorer ds = dw.scorer(r);
final boolean skipOk = ds.skipTo(3);
final boolean skipOk = ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS;
if (skipOk) {
fail("firsttime skipTo found a match? ... " +
r.document(ds.doc()).get("id"));
fail("firsttime skipTo found a match? ... " + r.document(ds.docID()).get("id"));
}
}
@ -152,8 +151,8 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase{
final Weight dw = dq.weight(s);
final Scorer ds = dw.scorer(r);
assertTrue("firsttime skipTo found no match", ds.skipTo(3));
assertEquals("found wrong docid", "d4", r.document(ds.doc()).get("id"));
assertTrue("firsttime skipTo found no match", ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS);
assertEquals("found wrong docid", "d4", r.document(ds.docID()).get("id"));
}

View File

@ -34,27 +34,37 @@ public class TestDocIdSet extends LuceneTestCase {
public DocIdSetIterator iterator() {
return new DocIdSetIterator() {
int docid=-1;
//@Override
int docid = -1;
/** @deprecated use {@link #docID()} instead. */
public int doc() {
return docid;
}
//@Override
public int docID() {
return docid;
}
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
docid++;
return (docid<maxdoc);
return nextDoc() != NO_MORE_DOCS;
}
//@Override
public boolean skipTo(int target) throws IOException {
do {
if (!next()) {
return false;
}
} while (target > doc());
public int nextDoc() throws IOException {
docid++;
return docid < maxdoc ? docid : (docid = NO_MORE_DOCS);
}
return true;
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
//@Override
public int advance(int target) throws IOException {
while (nextDoc() < target) {}
return docid;
}
};
}
@ -70,10 +80,11 @@ public class TestDocIdSet extends LuceneTestCase {
DocIdSetIterator iter = filteredSet.iterator();
ArrayList/*<Integer>*/ list = new ArrayList/*<Integer>*/();
if (iter.skipTo(3)) {
list.add(new Integer(iter.doc()));
while(iter.next()) {
list.add(new Integer(iter.doc()));
int doc = iter.advance(3);
if (doc != DocIdSetIterator.NO_MORE_DOCS) {
list.add(Integer.valueOf(doc));
while((doc = iter.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
list.add(Integer.valueOf(doc));
}
}

View File

@ -36,15 +36,28 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase {
return idx == scores.length ? Float.NaN : scores[idx];
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return idx; }
public int docID() { return idx; }
public boolean next() throws IOException {
return ++idx == scores.length;
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return nextDoc() != NO_MORE_DOCS;
}
public int nextDoc() throws IOException {
return ++idx != scores.length ? idx : NO_MORE_DOCS;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
idx = target;
return idx >= scores.length;
return idx < scores.length ? idx : NO_MORE_DOCS;
}
}
@ -71,7 +84,7 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase {
TopDocsCollector tdc = TopScoreDocCollector.create(scores.length, true);
Collector c = new PositiveScoresOnlyCollector(tdc);
c.setScorer(s);
while (!s.next()) {
while (s.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
c.collect(0);
}
TopDocs td = tdc.topDocs();

View File

@ -42,16 +42,30 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase {
return idx == scores.length ? Float.NaN : scores[idx++];
}
/** @deprecated use {@link #docID()} instead. */
public int doc() { return doc; }
public int docID() { return doc; }
/** @deprecated use {@link #nextDoc()} instead. */
public boolean next() throws IOException {
return ++doc == scores.length;
return nextDoc() != NO_MORE_DOCS;
}
public boolean skipTo(int target) throws IOException {
doc = target;
return doc >= scores.length;
public int nextDoc() throws IOException {
return ++doc < scores.length ? doc : NO_MORE_DOCS;
}
/** @deprecated use {@link #advance(int)} instead. */
public boolean skipTo(int target) throws IOException {
return advance(target) != NO_MORE_DOCS;
}
public int advance(int target) throws IOException {
doc = target;
return doc < scores.length ? doc : NO_MORE_DOCS;
}
}
private static final class ScoreCachingCollector extends Collector {
@ -98,8 +112,9 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase {
scc.setScorer(s);
// We need to iterate on the scorer so that its doc() advances.
while (!s.next()) {
scc.collect(s.doc());
int doc;
while ((doc = s.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
scc.collect(doc);
}
for (int i = 0; i < scores.length; i++) {

View File

@ -16,7 +16,9 @@ package org.apache.lucene.search;
* limitations under the License.
*/
import org.apache.lucene.util.LuceneTestCase;
import java.util.Iterator;
import java.util.List;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
@ -27,10 +29,7 @@ import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.English;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import org.apache.lucene.util.LuceneTestCase;
public class TestSpanQueryFilter extends LuceneTestCase {
@ -77,7 +76,7 @@ public class TestSpanQueryFilter extends LuceneTestCase {
int getDocIdSetSize(DocIdSet docIdSet) throws Exception {
int size = 0;
DocIdSetIterator it = docIdSet.iterator();
while (it.next()) {
while (it.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
size++;
}
return size;
@ -85,7 +84,7 @@ public class TestSpanQueryFilter extends LuceneTestCase {
public void assertContainsDocId(String msg, DocIdSet docIdSet, int docId) throws Exception {
DocIdSetIterator it = docIdSet.iterator();
assertTrue(msg, it.skipTo(docId));
assertTrue(msg, it.doc() == docId);
assertTrue(msg, it.advance(docId) != DocIdSetIterator.NO_MORE_DOCS);
assertTrue(msg, it.docID() == docId);
}
}

View File

@ -134,11 +134,11 @@ public class TestTermScorer extends LuceneTestCase
TermScorer ts = new TermScorer(weight,
indexReader.termDocs(allTerm), indexSearcher.getSimilarity(),
indexReader.norms(FIELD));
assertTrue("next did not return a doc", ts.next() == true);
assertTrue("next did not return a doc", ts.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertTrue("score is not correct", ts.score() == 1.6931472f);
assertTrue("next did not return a doc", ts.next() == true);
assertTrue("next did not return a doc", ts.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertTrue("score is not correct", ts.score() == 1.6931472f);
assertTrue("next returned a doc and it should not have", ts.next() == false);
assertTrue("next returned a doc and it should not have", ts.nextDoc() == DocIdSetIterator.NO_MORE_DOCS);
}
public void testSkipTo() throws Exception {
@ -151,7 +151,7 @@ public class TestTermScorer extends LuceneTestCase
TermScorer ts = new TermScorer(weight,
indexReader.termDocs(allTerm), indexSearcher.getSimilarity(),
indexReader.norms(FIELD));
assertTrue("Didn't skip", ts.skipTo(3) == true);
assertTrue("Didn't skip", ts.advance(3) != DocIdSetIterator.NO_MORE_DOCS);
//The next doc should be doc 5
assertTrue("doc should be number 5", ts.doc() == 5);
}

View File

@ -21,6 +21,8 @@ import java.io.IOException;
import java.util.Collection;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;
/**
* Holds all implementations of classes in the o.a.l.s.spans package as a
@ -109,4 +111,15 @@ final class JustCompileSearchSpans {
}
static final class JustCompileSpanScorer extends SpanScorer {
protected JustCompileSpanScorer(Spans spans, Weight weight,
Similarity similarity, byte[] norms) throws IOException {
super(spans, weight, similarity, norms);
}
protected boolean setFreqCurrentDoc() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
}

View File

@ -165,8 +165,7 @@ public class TestNearSpansOrdered extends LuceneTestCase {
SpanNearQuery q = makeQuery();
Weight w = q.createWeight(searcher);
Scorer s = w.scorer(searcher.getIndexReader());
assertEquals(true, s.skipTo(1));
assertEquals(1, s.doc());
assertEquals(1, s.advance(1));
}
/**
* not a direct test of NearSpans, but a demonstration of how/when

View File

@ -17,6 +17,7 @@ package org.apache.lucene.search.spans;
* limitations under the License.
*/
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.CheckHits;
@ -392,11 +393,11 @@ public class TestSpans extends LuceneTestCase {
Scorer spanScorer = snq.weight(searcher).scorer(searcher.getIndexReader());
assertTrue("first doc", spanScorer.next());
assertEquals("first doc number", spanScorer.doc(), 11);
assertTrue("first doc", spanScorer.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertEquals("first doc number", spanScorer.docID(), 11);
float score = spanScorer.score();
assertTrue("first doc score should be zero, " + score, score == 0.0f);
assertTrue("no second doc", ! spanScorer.next());
assertTrue("no second doc", spanScorer.nextDoc() == DocIdSetIterator.NO_MORE_DOCS);
}
// LUCENE-1404

View File

@ -20,6 +20,8 @@ package org.apache.lucene.util;
import java.util.Random;
import java.util.BitSet;
import org.apache.lucene.search.DocIdSetIterator;
/**
* @version $Id$
*/
@ -55,12 +57,8 @@ public class TestOpenBitSet extends LuceneTestCase {
OpenBitSetIterator iterator = new OpenBitSetIterator(b);
do {
aa = a.nextSetBit(aa+1);
if (rand.nextBoolean())
iterator.next();
else
iterator.skipTo(bb+1);
bb = iterator.doc();
assertEquals(aa,bb);
bb = rand.nextBoolean() ? iterator.nextDoc() : iterator.advance(bb + 1);
assertEquals(aa == -1 ? DocIdSetIterator.NO_MORE_DOCS : aa, bb);
} while (aa>=0);
}
@ -69,11 +67,8 @@ public class TestOpenBitSet extends LuceneTestCase {
OpenBitSetIterator iterator = new OpenBitSetIterator(b);
do {
aa = a.nextSetBit(aa+1);
if (rand.nextBoolean())
bb = iterator.nextDoc();
else
bb = iterator.next(bb+1);
assertEquals(aa,bb);
bb = rand.nextBoolean() ? iterator.nextDoc() : iterator.advance(bb + 1);
assertEquals(aa == -1 ? DocIdSetIterator.NO_MORE_DOCS : aa, bb);
} while (aa>=0);
}

View File

@ -42,10 +42,10 @@ public class TestSortedVIntList extends TestCase {
}
DocIdSetIterator m = vintList.iterator();
for (int i = 0; i < ints.length; i++) {
assertTrue("No end of Matcher at: " + i, m.next());
assertEquals(ints[i], m.doc());
assertTrue("No end of Matcher at: " + i, m.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertEquals(ints[i], m.docID());
}
assertTrue("End of Matcher", (! m.next()));
assertTrue("End of Matcher", m.nextDoc() == DocIdSetIterator.NO_MORE_DOCS);
}
void tstVIntList(
@ -143,9 +143,6 @@ public class TestSortedVIntList extends TestCase {
public void test02() {
tstInts(new int[] {0});
}
public void test03() {
tstInts(new int[] {0,Integer.MAX_VALUE});
}
public void test04a() {
tstInts(new int[] {0, VB2 - 1});
}