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:
Robert Muir 2023-02-17 08:25:17 -05:00 committed by GitHub
parent 8340b01c3c
commit 3ad2ede395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 92 additions and 65 deletions

View File

@ -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,13 +108,29 @@ 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);
// implement ScorerSupplier, since we do some expensive stuff to make a scorer
return new ScorerSupplier() {
@Override
public Scorer get(long leadCost) throws IOException {
final long minOrd; final long minOrd;
if (lowerValue == null) { if (lowerValue == null) {
minOrd = 0; minOrd = 0;
@ -141,8 +159,9 @@ final class SortedSetDocValuesRangeQuery extends Query {
} }
} }
// no terms matched in this segment
if (minOrd > maxOrd) { if (minOrd > maxOrd) {
return null; return new ConstantScoreScorer(weight, score(), scoreMode, DocIdSetIterator.empty());
} }
final SortedDocValues singleton = DocValues.unwrapSingleton(values); final SortedDocValues singleton = DocValues.unwrapSingleton(values);
@ -171,7 +190,8 @@ final class SortedSetDocValuesRangeQuery extends Query {
if (ord < minOrd) { if (ord < minOrd) {
continue; continue;
} }
// Values are sorted, so the first ord that is >= minOrd is our best candidate // Values are sorted, so the first ord that is >= minOrd is our best
// candidate
return ord <= maxOrd; return ord <= maxOrd;
} }
return false; // all ords were < minOrd return false; // all ords were < minOrd
@ -183,7 +203,14 @@ final class SortedSetDocValuesRangeQuery extends Query {
} }
}; };
} }
return new ConstantScoreScorer(this, score(), scoreMode, iterator); return new ConstantScoreScorer(weight, score(), scoreMode, iterator);
}
@Override
public long cost() {
return values.cost();
}
};
} }
@Override @Override