mirror of https://github.com/apache/lucene.git
LUCENE-8103: Use TwoPhaseIterator in DoubleValuesSource and QueryValueSource
Fixes #1343
This commit is contained in:
parent
bd16620706
commit
87b1bddf1c
|
@ -122,6 +122,9 @@ Optimizations
|
|||
|
||||
* LUCENE-9254: UniformSplit keeps FST off-heap. (Bruno Roustant)
|
||||
|
||||
* LUCENE-8103: DoubleValuesSource and QueryValueSource now use a TwoPhaseIterator if one is provided by the Query.
|
||||
(Michele Palmia, David Smiley)
|
||||
|
||||
Bug Fixes
|
||||
---------------------
|
||||
* LUCENE-9259: Fix wrong NGramFilterFactory argument name for preserveOriginal option (Paul Pazderski)
|
||||
|
|
|
@ -604,8 +604,11 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
|
|||
Scorer scorer = weight.scorer(ctx);
|
||||
if (scorer == null)
|
||||
return DoubleValues.EMPTY;
|
||||
DocIdSetIterator it = scorer.iterator();
|
||||
|
||||
return new DoubleValues() {
|
||||
private final TwoPhaseIterator tpi = scorer.twoPhaseIterator();
|
||||
private final DocIdSetIterator disi = (tpi == null) ? scorer.iterator() : tpi.approximation();
|
||||
|
||||
@Override
|
||||
public double doubleValue() throws IOException {
|
||||
return scorer.score();
|
||||
|
@ -613,9 +616,10 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
|
|||
|
||||
@Override
|
||||
public boolean advanceExact(int doc) throws IOException {
|
||||
if (it.docID() > doc)
|
||||
return false;
|
||||
return it.docID() == doc || it.advance(doc) == doc;
|
||||
if (disi.docID() < doc) {
|
||||
disi.advance(doc);
|
||||
}
|
||||
return disi.docID() == doc && (tpi == null || tpi.matches());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -274,7 +274,17 @@ public class TestDoubleValuesSource extends LuceneTestCase {
|
|||
}
|
||||
|
||||
public void testQueryDoubleValuesSource() throws Exception {
|
||||
Query q = new TermQuery(new Term("english", "two"));
|
||||
Query iteratingQuery = new TermQuery(new Term("english", "two"));
|
||||
Query approximatingQuery = new PhraseQuery.Builder()
|
||||
.add(new Term("english", "hundred"), 0)
|
||||
.add(new Term("english", "one"), 1)
|
||||
.build();
|
||||
|
||||
doTestQueryDoubleValuesSources(iteratingQuery);
|
||||
doTestQueryDoubleValuesSources(approximatingQuery);
|
||||
}
|
||||
|
||||
private void doTestQueryDoubleValuesSources(Query q) throws Exception {
|
||||
DoubleValuesSource vs = DoubleValuesSource.fromQuery(q).rewrite(searcher);
|
||||
searcher.search(q, new SimpleCollector() {
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.lucene.search.IndexSearcher;
|
|||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.ScoreMode;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
import org.apache.lucene.search.TwoPhaseIterator;
|
||||
import org.apache.lucene.search.Weight;
|
||||
import org.apache.lucene.util.mutable.MutableValue;
|
||||
import org.apache.lucene.util.mutable.MutableValueFloat;
|
||||
|
@ -87,14 +88,13 @@ class QueryDocValues extends FloatDocValues {
|
|||
final Query q;
|
||||
|
||||
Scorer scorer;
|
||||
DocIdSetIterator it;
|
||||
int scorerDoc; // the document the scorer is on
|
||||
boolean noMatches=false;
|
||||
DocIdSetIterator disi;
|
||||
TwoPhaseIterator tpi;
|
||||
Boolean thisDocMatches;
|
||||
|
||||
// the last document requested
|
||||
int lastDocRequested=-1;
|
||||
|
||||
// the last document requested... start off with high value
|
||||
// to trigger a scorer reset on first access.
|
||||
int lastDocRequested=Integer.MAX_VALUE;
|
||||
|
||||
|
||||
public QueryDocValues(QueryValueSource vs, LeafReaderContext readerContext, Map fcontext) throws IOException {
|
||||
super(vs);
|
||||
|
@ -124,30 +124,7 @@ class QueryDocValues extends FloatDocValues {
|
|||
@Override
|
||||
public float floatVal(int doc) {
|
||||
try {
|
||||
if (doc < lastDocRequested) {
|
||||
if (noMatches) return defVal;
|
||||
scorer = weight.scorer(readerContext);
|
||||
if (scorer==null) {
|
||||
noMatches = true;
|
||||
return defVal;
|
||||
}
|
||||
it = scorer.iterator();
|
||||
scorerDoc = -1;
|
||||
}
|
||||
lastDocRequested = doc;
|
||||
|
||||
if (scorerDoc < doc) {
|
||||
scorerDoc = it.advance(doc);
|
||||
}
|
||||
|
||||
if (scorerDoc > doc) {
|
||||
// query doesn't match this document... either because we hit the
|
||||
// end, or because the next doc is after this doc.
|
||||
return defVal;
|
||||
}
|
||||
|
||||
// a match!
|
||||
return scorer.score();
|
||||
return exists(doc) ? scorer.score() : defVal;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("caught exception in QueryDocVals("+q+") doc="+doc, e);
|
||||
}
|
||||
|
@ -155,31 +132,33 @@ class QueryDocValues extends FloatDocValues {
|
|||
|
||||
@Override
|
||||
public boolean exists(int doc) {
|
||||
if (doc < lastDocRequested) {
|
||||
throw new IllegalArgumentException("docs were sent out-of-order: lastDocID=" + lastDocRequested + " vs docID=" + doc);
|
||||
}
|
||||
lastDocRequested = doc;
|
||||
|
||||
try {
|
||||
if (doc < lastDocRequested) {
|
||||
if (noMatches) return false;
|
||||
if (disi == null) {
|
||||
scorer = weight.scorer(readerContext);
|
||||
scorerDoc = -1;
|
||||
if (scorer==null) {
|
||||
noMatches = true;
|
||||
return false;
|
||||
if (scorer == null) {
|
||||
disi = DocIdSetIterator.empty();
|
||||
} else {
|
||||
tpi = scorer.twoPhaseIterator();
|
||||
disi = tpi == null ? scorer.iterator() : tpi.approximation();
|
||||
}
|
||||
it = scorer.iterator();
|
||||
}
|
||||
lastDocRequested = doc;
|
||||
|
||||
if (scorerDoc < doc) {
|
||||
scorerDoc = it.advance(doc);
|
||||
thisDocMatches = null;
|
||||
}
|
||||
|
||||
if (scorerDoc > doc) {
|
||||
// query doesn't match this document... either because we hit the
|
||||
// end, or because the next doc is after this doc.
|
||||
return false;
|
||||
if (disi.docID() < doc) {
|
||||
disi.advance(doc);
|
||||
thisDocMatches = null;
|
||||
}
|
||||
|
||||
// a match!
|
||||
return true;
|
||||
if (disi.docID() == doc) {
|
||||
if (thisDocMatches == null) {
|
||||
thisDocMatches = tpi == null || tpi.matches();
|
||||
}
|
||||
return thisDocMatches;
|
||||
} else return false;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("caught exception in QueryDocVals("+q+") doc="+doc, e);
|
||||
}
|
||||
|
@ -187,11 +166,7 @@ class QueryDocValues extends FloatDocValues {
|
|||
|
||||
@Override
|
||||
public Object objectVal(int doc) {
|
||||
try {
|
||||
return exists(doc) ? scorer.score() : null;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("caught exception in QueryDocVals("+q+") doc="+doc, e);
|
||||
}
|
||||
return floatVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -212,37 +187,13 @@ class QueryDocValues extends FloatDocValues {
|
|||
@Override
|
||||
public void fillValue(int doc) {
|
||||
try {
|
||||
if (noMatches) {
|
||||
if (exists(doc)) {
|
||||
mval.value = scorer.score();
|
||||
mval.exists = true;
|
||||
} else {
|
||||
mval.value = defVal;
|
||||
mval.exists = false;
|
||||
return;
|
||||
}
|
||||
scorer = weight.scorer(readerContext);
|
||||
scorerDoc = -1;
|
||||
if (scorer==null) {
|
||||
noMatches = true;
|
||||
mval.value = defVal;
|
||||
mval.exists = false;
|
||||
return;
|
||||
}
|
||||
it = scorer.iterator();
|
||||
lastDocRequested = doc;
|
||||
|
||||
if (scorerDoc < doc) {
|
||||
scorerDoc = it.advance(doc);
|
||||
}
|
||||
|
||||
if (scorerDoc > doc) {
|
||||
// query doesn't match this document... either because we hit the
|
||||
// end, or because the next doc is after this doc.
|
||||
mval.value = defVal;
|
||||
mval.exists = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// a match!
|
||||
mval.value = scorer.score();
|
||||
mval.exists = true;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("caught exception in QueryDocVals("+q+") doc="+doc, e);
|
||||
}
|
||||
|
|
|
@ -379,6 +379,10 @@ public class TestValueSources extends LuceneTestCase {
|
|||
ValueSource vs = new QueryValueSource(new FunctionQuery(new ConstValueSource(2f)), 0f);
|
||||
assertHits(new FunctionQuery(vs), new float[] { 2f, 2f });
|
||||
assertAllExist(vs);
|
||||
|
||||
vs = new QueryValueSource(new FunctionRangeQuery(new IntFieldSource("int"), Integer.MIN_VALUE, Integer.MAX_VALUE, true, true), 0f);
|
||||
assertHits(new FunctionQuery(vs), new float[] { 35f, 54f });
|
||||
assertAllExist(vs);
|
||||
}
|
||||
|
||||
public void testQuery() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue