LUCENE-9114: Improve ValueSourceScorer's Default Cost Implementation (#1303)

This commit makes ValueSourceScorer's costing algorithm also take the delegated FunctionValues's cost into consideration when calculating its cost. FunctionValues now exposes a cost method which is used by ValueSourceScorer's default matchCost method. In addition, ValueSourceScorer exposes a matchCost method which can be overridden to specify a custom costing mechanism
This commit is contained in:
Atri Sharma 2020-03-05 09:16:50 +05:30 committed by GitHub
parent f6afb8b165
commit d751cf626e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 1 deletions

View File

@ -79,6 +79,8 @@ Improvements
Nepali, Serbian, and Tamil. New stoplist: Indonesian. Adds gradle 'snowball'
task to regenerate and ease future upgrades. (Robert Muir, Dawid Weiss)
* LUCENE-9114: Improve ValueSourceScorer's Default Cost Implementation (Atri Sharma)
Bug fixes
* LUCENE-8663: NRTCachingDirectory.slowFileExists may open a file while

View File

@ -90,6 +90,16 @@ public abstract class FunctionValues {
* @return the number of unique sort ordinals this instance has
*/
public int numOrd() { throw new UnsupportedOperationException(); }
/**
* An estimate of the expected cost to return a value for a document.
* It's intended to be used by TwoPhaseIterator.matchCost implementations.
* Returns an expected cost in number of simple operations like addition, multiplication,
* comparing two numbers and indexing an array.
* The returned value must be positive.
*/
public float cost() { return 100; }
public abstract String toString(int doc) throws IOException;
/**
@ -151,6 +161,10 @@ public abstract class FunctionValues {
public boolean matches(int doc) {
return true;
}
@Override
public float matchCost() {
return 0f;
}
};
}

View File

@ -39,6 +39,9 @@ import org.apache.lucene.search.Weight;
* @lucene.experimental
*/
public abstract class ValueSourceScorer extends Scorer {
// Fixed cost for a single iteration of the TwoPhaseIterator instance
private static final int DEF_COST = 5;
protected final FunctionValues values;
private final TwoPhaseIterator twoPhaseIterator;
private final DocIdSetIterator disi;
@ -55,7 +58,7 @@ public abstract class ValueSourceScorer extends Scorer {
@Override
public float matchCost() {
return 100; // TODO: use cost of ValueSourceScorer.this.matches()
return ValueSourceScorer.this.matchCost();
}
};
this.disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseIterator);
@ -94,4 +97,17 @@ public abstract class ValueSourceScorer extends Scorer {
return Float.POSITIVE_INFINITY;
}
/**
* Cost evaluation function which defines the cost of access for the TwoPhaseIterator for this class
* This method should be overridden for specifying custom cost methods. Used by {@link TwoPhaseIterator#matchCost()}
* for the instance owned by this class
*
* @return cost of access
*
* @lucene.experimental
*/
protected float matchCost() {
// Cost of iteration is fixed cost + cost exposed by delegated FunctionValues instance
return DEF_COST + values.cost();
}
}

View File

@ -22,6 +22,8 @@ import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@ -137,6 +139,19 @@ public class TestFunctionRangeQuery extends FunctionTestSetup {
explain.toString());
}
@Test
public void testTwoRangeQueries() throws IOException {
Query rq1 = new FunctionRangeQuery(INT_VALUESOURCE, 2, 4, true, true);
Query rq2 = new FunctionRangeQuery(INT_VALUESOURCE, 8, 10, true, true);
Query bq = new BooleanQuery.Builder()
.add(rq1, BooleanClause.Occur.SHOULD)
.add(rq2, BooleanClause.Occur.SHOULD)
.build();
ScoreDoc[] scoreDocs = indexSearcher.search(bq, N_DOCS).scoreDocs;
expectScores(scoreDocs, 10, 9, 8, 4, 3, 2);
}
private void expectScores(ScoreDoc[] scoreDocs, int... docScores) {
assertEquals(docScores.length, scoreDocs.length);
for (int i = 0; i < docScores.length; i++) {