mirror of https://github.com/apache/lucene.git
Implement ScorerSupplier for Sorted(Set)DocValuesField#newSlowRangeQuery (#12132)
Similar to use of ScorerSupplier in #12129, implement it here too, because creation of a Scorer requires lookupTerm() operations in the DV terms dictionary. This results in wasted effort/random accesses, if, based on the cost(), IndexOrDocValuesQuery decides not to use this query.
This commit is contained in:
parent
8340b01c3c
commit
3ad2ede395
|
@ -24,12 +24,14 @@ import org.apache.lucene.index.SortedDocValues;
|
||||||
import org.apache.lucene.index.SortedSetDocValues;
|
import org.apache.lucene.index.SortedSetDocValues;
|
||||||
import org.apache.lucene.search.ConstantScoreScorer;
|
import org.apache.lucene.search.ConstantScoreScorer;
|
||||||
import org.apache.lucene.search.ConstantScoreWeight;
|
import org.apache.lucene.search.ConstantScoreWeight;
|
||||||
|
import org.apache.lucene.search.DocIdSetIterator;
|
||||||
import org.apache.lucene.search.FieldExistsQuery;
|
import org.apache.lucene.search.FieldExistsQuery;
|
||||||
import org.apache.lucene.search.IndexSearcher;
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.QueryVisitor;
|
import org.apache.lucene.search.QueryVisitor;
|
||||||
import org.apache.lucene.search.ScoreMode;
|
import org.apache.lucene.search.ScoreMode;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
|
import org.apache.lucene.search.ScorerSupplier;
|
||||||
import org.apache.lucene.search.TwoPhaseIterator;
|
import org.apache.lucene.search.TwoPhaseIterator;
|
||||||
import org.apache.lucene.search.Weight;
|
import org.apache.lucene.search.Weight;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
@ -106,84 +108,109 @@ final class SortedSetDocValuesRangeQuery extends Query {
|
||||||
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost)
|
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return new ConstantScoreWeight(this, boost) {
|
return new ConstantScoreWeight(this, boost) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Scorer scorer(LeafReaderContext context) throws IOException {
|
public Scorer scorer(LeafReaderContext context) throws IOException {
|
||||||
|
ScorerSupplier scorerSupplier = scorerSupplier(context);
|
||||||
|
if (scorerSupplier == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return scorerSupplier.get(Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
|
||||||
|
final Weight weight = this;
|
||||||
if (context.reader().getFieldInfos().fieldInfo(field) == null) {
|
if (context.reader().getFieldInfos().fieldInfo(field) == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SortedSetDocValues values = DocValues.getSortedSet(context.reader(), field);
|
SortedSetDocValues values = DocValues.getSortedSet(context.reader(), field);
|
||||||
|
|
||||||
final long minOrd;
|
// implement ScorerSupplier, since we do some expensive stuff to make a scorer
|
||||||
if (lowerValue == null) {
|
return new ScorerSupplier() {
|
||||||
minOrd = 0;
|
@Override
|
||||||
} else {
|
public Scorer get(long leadCost) throws IOException {
|
||||||
final long ord = values.lookupTerm(lowerValue);
|
|
||||||
if (ord < 0) {
|
|
||||||
minOrd = -1 - ord;
|
|
||||||
} else if (lowerInclusive) {
|
|
||||||
minOrd = ord;
|
|
||||||
} else {
|
|
||||||
minOrd = ord + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final long maxOrd;
|
final long minOrd;
|
||||||
if (upperValue == null) {
|
if (lowerValue == null) {
|
||||||
maxOrd = values.getValueCount() - 1;
|
minOrd = 0;
|
||||||
} else {
|
} else {
|
||||||
final long ord = values.lookupTerm(upperValue);
|
final long ord = values.lookupTerm(lowerValue);
|
||||||
if (ord < 0) {
|
if (ord < 0) {
|
||||||
maxOrd = -2 - ord;
|
minOrd = -1 - ord;
|
||||||
} else if (upperInclusive) {
|
} else if (lowerInclusive) {
|
||||||
maxOrd = ord;
|
minOrd = ord;
|
||||||
} else {
|
} else {
|
||||||
maxOrd = ord - 1;
|
minOrd = ord + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minOrd > maxOrd) {
|
final long maxOrd;
|
||||||
return null;
|
if (upperValue == null) {
|
||||||
}
|
maxOrd = values.getValueCount() - 1;
|
||||||
|
} else {
|
||||||
|
final long ord = values.lookupTerm(upperValue);
|
||||||
|
if (ord < 0) {
|
||||||
|
maxOrd = -2 - ord;
|
||||||
|
} else if (upperInclusive) {
|
||||||
|
maxOrd = ord;
|
||||||
|
} else {
|
||||||
|
maxOrd = ord - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final SortedDocValues singleton = DocValues.unwrapSingleton(values);
|
// no terms matched in this segment
|
||||||
final TwoPhaseIterator iterator;
|
if (minOrd > maxOrd) {
|
||||||
if (singleton != null) {
|
return new ConstantScoreScorer(weight, score(), scoreMode, DocIdSetIterator.empty());
|
||||||
iterator =
|
}
|
||||||
new TwoPhaseIterator(singleton) {
|
|
||||||
@Override
|
|
||||||
public boolean matches() throws IOException {
|
|
||||||
final long ord = singleton.ordValue();
|
|
||||||
return ord >= minOrd && ord <= maxOrd;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
final SortedDocValues singleton = DocValues.unwrapSingleton(values);
|
||||||
public float matchCost() {
|
final TwoPhaseIterator iterator;
|
||||||
return 2; // 2 comparisons
|
if (singleton != null) {
|
||||||
}
|
iterator =
|
||||||
};
|
new TwoPhaseIterator(singleton) {
|
||||||
} else {
|
@Override
|
||||||
iterator =
|
public boolean matches() throws IOException {
|
||||||
new TwoPhaseIterator(values) {
|
final long ord = singleton.ordValue();
|
||||||
@Override
|
return ord >= minOrd && ord <= maxOrd;
|
||||||
public boolean matches() throws IOException {
|
|
||||||
for (int i = 0; i < values.docValueCount(); i++) {
|
|
||||||
long ord = values.nextOrd();
|
|
||||||
if (ord < minOrd) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// Values are sorted, so the first ord that is >= minOrd is our best candidate
|
|
||||||
return ord <= maxOrd;
|
|
||||||
}
|
|
||||||
return false; // all ords were < minOrd
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float matchCost() {
|
public float matchCost() {
|
||||||
return 2; // 2 comparisons
|
return 2; // 2 comparisons
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
return new ConstantScoreScorer(this, score(), scoreMode, iterator);
|
iterator =
|
||||||
|
new TwoPhaseIterator(values) {
|
||||||
|
@Override
|
||||||
|
public boolean matches() throws IOException {
|
||||||
|
for (int i = 0; i < values.docValueCount(); i++) {
|
||||||
|
long ord = values.nextOrd();
|
||||||
|
if (ord < minOrd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Values are sorted, so the first ord that is >= minOrd is our best
|
||||||
|
// candidate
|
||||||
|
return ord <= maxOrd;
|
||||||
|
}
|
||||||
|
return false; // all ords were < minOrd
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float matchCost() {
|
||||||
|
return 2; // 2 comparisons
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new ConstantScoreScorer(weight, score(), scoreMode, iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long cost() {
|
||||||
|
return values.cost();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue