add assertion for cast double->float
ScoreFunction scoring might result in under or overflow, for example if a user decides to use the timestamp as a boost in the script scorer. Therefore, check if cast causes a huge precision loss. Note that this does not always detect casting issues. For example in ScriptFunction.score() the function SearchScript.runAsDouble() is called. AbstractFloatSearchScript implements it as follows: @Override public double runAsDouble() { return runAsFloat(); } In this case the cast happens before the assertion and therfore precision lossor over/underflows cannot be detected by the assertion.
This commit is contained in:
parent
e707308f1f
commit
a938bd57a9
|
@ -33,7 +33,6 @@ public class BoostScoreFunction implements ScoreFunction {
|
|||
this.boost = boost;
|
||||
}
|
||||
|
||||
|
||||
public float getBoost() {
|
||||
return boost;
|
||||
}
|
||||
|
@ -44,7 +43,7 @@ public class BoostScoreFunction implements ScoreFunction {
|
|||
}
|
||||
|
||||
@Override
|
||||
public float score(int docId, float subQueryScore) {
|
||||
public double score(int docId, float subQueryScore) {
|
||||
return subQueryScore * boost;
|
||||
}
|
||||
|
||||
|
@ -68,12 +67,15 @@ public class BoostScoreFunction implements ScoreFunction {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
BoostScoreFunction that = (BoostScoreFunction) o;
|
||||
|
||||
if (Float.compare(that.boost, boost) != 0) return false;
|
||||
if (Float.compare(that.boost, boost) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -164,11 +164,11 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
if (docSet.get(doc)) {
|
||||
filterFunction.function.setNextReader(context);
|
||||
Explanation functionExplanation = filterFunction.function.explainFactor(doc);
|
||||
float factor = functionExplanation.getValue();
|
||||
double factor = functionExplanation.getValue();
|
||||
if (factor > maxBoost) {
|
||||
factor = maxBoost;
|
||||
}
|
||||
float sc = getBoost() * factor;
|
||||
float sc = toFloat(getBoost() * factor);
|
||||
Explanation filterExplanation = new ComplexExplanation(true, sc, "custom score, product of:");
|
||||
filterExplanation.addDetail(new Explanation(1.0f, "match filter: " + filterFunction.filter.toString()));
|
||||
filterExplanation.addDetail(functionExplanation);
|
||||
|
@ -186,21 +186,21 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
int count = 0;
|
||||
float total = 0;
|
||||
float multiply = 1;
|
||||
float max = Float.NEGATIVE_INFINITY;
|
||||
float min = Float.POSITIVE_INFINITY;
|
||||
double max = Double.NEGATIVE_INFINITY;
|
||||
double min = Double.POSITIVE_INFINITY;
|
||||
ArrayList<Explanation> filtersExplanations = new ArrayList<Explanation>();
|
||||
for (FilterFunction filterFunction : filterFunctions) {
|
||||
Bits docSet = DocIdSets.toSafeBits(context.reader(), filterFunction.filter.getDocIdSet(context, context.reader().getLiveDocs()));
|
||||
if (docSet.get(doc)) {
|
||||
filterFunction.function.setNextReader(context);
|
||||
Explanation functionExplanation = filterFunction.function.explainFactor(doc);
|
||||
float factor = functionExplanation.getValue();
|
||||
double factor = functionExplanation.getValue();
|
||||
count++;
|
||||
total += factor;
|
||||
multiply *= factor;
|
||||
max = Math.max(factor, max);
|
||||
min = Math.min(factor, min);
|
||||
Explanation res = new ComplexExplanation(true, factor, "custom score, product of:");
|
||||
Explanation res = new ComplexExplanation(true, toFloat(factor), "custom score, product of:");
|
||||
res.addDetail(new Explanation(1.0f, "match filter: " + filterFunction.filter.toString()));
|
||||
res.addDetail(functionExplanation);
|
||||
res.addDetail(new Explanation(getBoost(), "queryBoost"));
|
||||
|
@ -208,7 +208,7 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
float factor = 0;
|
||||
double factor = 0;
|
||||
switch (scoreMode) {
|
||||
case Avg:
|
||||
factor = total / count;
|
||||
|
@ -230,7 +230,7 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
if (factor > maxBoost) {
|
||||
factor = maxBoost;
|
||||
}
|
||||
float sc = factor * subQueryExpl.getValue() * getBoost();
|
||||
float sc = toFloat(factor * subQueryExpl.getValue() * getBoost());
|
||||
Explanation res = new ComplexExplanation(true, sc, "custom score, score mode [" + scoreMode.toString().toLowerCase(Locale.ROOT) + "]");
|
||||
res.addDetail(subQueryExpl);
|
||||
for (Explanation explanation : filtersExplanations) {
|
||||
|
@ -341,7 +341,7 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
factor = maxBoost;
|
||||
}
|
||||
float score = scorer.score();
|
||||
return (float)(subQueryBoost * score * factor);
|
||||
return toFloat(subQueryBoost * score * factor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -381,5 +381,10 @@ public class FiltersFunctionScoreQuery extends Query {
|
|||
public int hashCode() {
|
||||
return subQuery.hashCode() + 31 * Arrays.hashCode(filterFunctions) ^ Float.floatToIntBits(getBoost());
|
||||
}
|
||||
|
||||
public static float toFloat(double input) {
|
||||
assert Double.compare(((float) input), input) == 0 || (Math.abs(((float) input) - input) <= 0.001);
|
||||
return (float) input;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class FunctionScoreQuery extends Query {
|
|||
@Override
|
||||
public Query rewrite(IndexReader reader) throws IOException {
|
||||
Query newQ = subQuery.rewrite(reader);
|
||||
if (newQ == subQuery){
|
||||
if (newQ == subQuery) {
|
||||
return this;
|
||||
}
|
||||
FunctionScoreQuery bq = (FunctionScoreQuery) this.clone();
|
||||
|
@ -165,8 +165,8 @@ public class FunctionScoreQuery extends Query {
|
|||
|
||||
@Override
|
||||
public float score() throws IOException {
|
||||
float factor = (float)function.score(scorer.docID(), scorer.score());
|
||||
return subQueryBoost * Math.min(maxBoost, factor);
|
||||
double factor = function.score(scorer.docID(), scorer.score());
|
||||
return toFloat(subQueryBoost * Math.min(maxBoost, factor));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,4 +198,10 @@ public class FunctionScoreQuery extends Query {
|
|||
public int hashCode() {
|
||||
return subQuery.hashCode() + 31 * function.hashCode() ^ Float.floatToIntBits(getBoost());
|
||||
}
|
||||
|
||||
public static float toFloat(double input) {
|
||||
assert Double.compare(((float) input), input) == 0 || (Math.abs(((float) input) - input) <= 0.001);
|
||||
return (float) input;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public interface ScoreFunction {
|
|||
|
||||
void setNextReader(AtomicReaderContext context);
|
||||
|
||||
float score(int docId, float subQueryScore);
|
||||
double score(int docId, float subQueryScore);
|
||||
|
||||
double factor(int docId);
|
||||
|
||||
|
|
|
@ -46,10 +46,10 @@ public class ScriptScoreFunction implements ScoreFunction {
|
|||
}
|
||||
|
||||
@Override
|
||||
public float score(int docId, float subQueryScore) {
|
||||
public double score(int docId, float subQueryScore) {
|
||||
script.setNextDocId(docId);
|
||||
script.setNextScore(subQueryScore);
|
||||
return script.runAsFloat();
|
||||
return script.runAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -359,8 +359,8 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public float score(int docId, float subQueryScore) {
|
||||
return (float) (subQueryScore * factor(docId));
|
||||
public double score(int docId, float subQueryScore) {
|
||||
return (subQueryScore * factor(docId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue