use factor in scripts, so custom score function will work correctly when it multiplies

This commit is contained in:
Shay Banon 2012-01-04 21:53:26 +02:00
parent 7d0af6a345
commit e5f2ce0fd6
6 changed files with 63 additions and 33 deletions

View File

@ -49,13 +49,23 @@ public class BoostScoreFunction implements ScoreFunction {
}
@Override
public Explanation explain(int docId, Explanation subQueryExpl) {
public float factor(int docId) {
return boost;
}
@Override
public Explanation explainScore(int docId, Explanation subQueryExpl) {
Explanation exp = new Explanation(boost * subQueryExpl.getValue(), "static boost function: product of:");
exp.addDetail(subQueryExpl);
exp.addDetail(new Explanation(boost, "boostFactor"));
return exp;
}
@Override
public Explanation explainFactor(int docId) {
return new Explanation(boost, "boostFactor");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -72,4 +82,9 @@ public class BoostScoreFunction implements ScoreFunction {
public int hashCode() {
return (boost != +0.0f ? Float.floatToIntBits(boost) : 0);
}
@Override
public String toString() {
return "boost[" + boost + "]";
}
}

View File

@ -34,8 +34,6 @@ import java.util.Set;
/**
* A query that allows for a pluggable boost function / filter. If it matches the filter, it will
* be boosted by the formula.
*
*
*/
public class FiltersFunctionScoreQuery extends Query {
@ -166,7 +164,7 @@ public class FiltersFunctionScoreQuery extends Query {
DocSet docSet = DocSets.convert(reader, filterFunction.filter.getDocIdSet(reader));
if (docSet.get(doc)) {
filterFunction.function.setNextReader(reader);
Explanation functionExplanation = filterFunction.function.explain(doc, subQueryExpl);
Explanation functionExplanation = filterFunction.function.explainFactor(doc);
float sc = getValue() * functionExplanation.getValue();
Explanation res = new ComplexExplanation(true, sc, "custom score, product of:");
res.addDetail(new Explanation(1.0f, "match filter: " + filterFunction.filter.toString()));
@ -186,7 +184,7 @@ public class FiltersFunctionScoreQuery extends Query {
DocSet docSet = DocSets.convert(reader, filterFunction.filter.getDocIdSet(reader));
if (docSet.get(doc)) {
filterFunction.function.setNextReader(reader);
Explanation functionExplanation = filterFunction.function.explain(doc, subQueryExpl);
Explanation functionExplanation = filterFunction.function.explainFactor(doc);
float sc = functionExplanation.getValue();
count++;
total += sc;
@ -221,6 +219,7 @@ public class FiltersFunctionScoreQuery extends Query {
}
sc *= getValue();
Explanation res = new ComplexExplanation(true, sc, "custom score, score mode [" + scoreMode.toString().toLowerCase() + "]");
res.addDetail(subQueryExpl);
for (Explanation explanation : filtersExplanations) {
res.addDetail(explanation);
}
@ -272,56 +271,58 @@ public class FiltersFunctionScoreQuery extends Query {
@Override
public float score() throws IOException {
int docId = scorer.docID();
float score = scorer.score();
float factor = 1.0f;
if (scoreMode == ScoreMode.First) {
for (int i = 0; i < filterFunctions.length; i++) {
if (docSets[i].get(docId)) {
return subQueryWeight * filterFunctions[i].function.score(docId, score);
factor = filterFunctions[i].function.factor(docId);
break;
}
}
} else if (scoreMode == ScoreMode.Max) {
float maxScore = Float.NEGATIVE_INFINITY;
float maxFactor = Float.NEGATIVE_INFINITY;
for (int i = 0; i < filterFunctions.length; i++) {
if (docSets[i].get(docId)) {
maxScore = Math.max(filterFunctions[i].function.score(docId, score), maxScore);
maxFactor = Math.max(filterFunctions[i].function.factor(docId), maxFactor);
}
}
if (maxScore != Float.NEGATIVE_INFINITY) {
score = maxScore;
if (maxFactor != Float.NEGATIVE_INFINITY) {
factor = maxFactor;
}
} else if (scoreMode == ScoreMode.Min) {
float minScore = Float.POSITIVE_INFINITY;
float minFactor = Float.POSITIVE_INFINITY;
for (int i = 0; i < filterFunctions.length; i++) {
if (docSets[i].get(docId)) {
minScore = Math.min(filterFunctions[i].function.score(docId, score), minScore);
minFactor = Math.min(filterFunctions[i].function.factor(docId), minFactor);
}
}
if (minScore != Float.POSITIVE_INFINITY) {
score = minScore;
if (minFactor != Float.POSITIVE_INFINITY) {
factor = minFactor;
}
} else if (scoreMode == ScoreMode.Multiply) {
for (int i = 0; i < filterFunctions.length; i++) {
if (docSets[i].get(docId)) {
factor *= filterFunctions[i].function.factor(docId);
}
}
} else { // Avg / Total
float totalScore = 0.0f;
float multiplicativeScore = 1.0f;
float totalFactor = 0.0f;
int count = 0;
for (int i = 0; i < filterFunctions.length; i++) {
if (docSets[i].get(docId)) {
float tempScore = filterFunctions[i].function.score(docId, score);
totalScore += tempScore;
multiplicativeScore *= tempScore;
totalFactor += filterFunctions[i].function.factor(docId);
count++;
}
}
if (count != 0) {
score = totalScore;
factor = totalFactor;
if (scoreMode == ScoreMode.Avg) {
score /= count;
}
else if (scoreMode == ScoreMode.Multiply) {
score = multiplicativeScore;
factor /= count;
}
}
}
return subQueryWeight * score;
float score = scorer.score();
return subQueryWeight * score * factor;
}
}

View File

@ -29,8 +29,6 @@ import java.util.Set;
/**
* A query that allows for a pluggable boost function to be applied to it.
*
*
*/
public class FunctionScoreQuery extends Query {
@ -117,7 +115,7 @@ public class FunctionScoreQuery extends Query {
}
function.setNextReader(reader);
Explanation functionExplanation = function.explain(doc, subQueryExpl);
Explanation functionExplanation = function.explainScore(doc, subQueryExpl);
float sc = getValue() * functionExplanation.getValue();
Explanation res = new ComplexExplanation(true, sc, "custom score, product of:");
res.addDetail(functionExplanation);

View File

@ -31,5 +31,9 @@ public interface ScoreFunction {
float score(int docId, float subQueryScore);
Explanation explain(int docId, Explanation subQueryExpl);
float factor(int docId);
Explanation explainScore(int docId, Explanation subQueryExpl);
Explanation explainFactor(int docId);
}

View File

@ -125,13 +125,25 @@ public class CustomScoreQueryParser implements QueryParser {
}
@Override
public Explanation explain(int docId, Explanation subQueryExpl) {
public float factor(int docId) {
// just the factor, so don't provide _score
script.setNextDocId(docId);
return script.runAsFloat();
}
@Override
public Explanation explainScore(int docId, Explanation subQueryExpl) {
float score = score(docId, subQueryExpl.getValue());
Explanation exp = new Explanation(score, "script score function: product of:");
exp.addDetail(subQueryExpl);
return exp;
}
@Override
public Explanation explainFactor(int docId) {
return new Explanation(factor(docId), "scriptFactor");
}
@Override
public String toString() {
return "script[" + sScript + "], params [" + params + "]";

View File

@ -164,8 +164,8 @@ public class CustomScoreSearchTests extends AbstractNodesTests {
SearchResponse searchResponse = client.prepareSearch("test")
.setQuery(customFiltersScoreQuery(matchAllQuery())
.add(termFilter("field", "value4"), "_score * 2")
.add(termFilter("field", "value2"), "_score * 3"))
.add(termFilter("field", "value4"), "2")
.add(termFilter("field", "value2"), "3"))
.setExplain(true)
.execute().actionGet();