Scripting: Add explicit error message when script_score script returns NaN
When a scoring script returns not a number, the current message is confusing (IllegalArgumentException[docID must be >= 0 and < maxDoc=3 (got docID=2147483647)]). This commit adds the error message ScriptException[script score function returns a wrong score: NaN]. Closes #2426
This commit is contained in:
parent
7b64a5c2c8
commit
a046ee756d
|
@ -22,6 +22,7 @@ package org.elasticsearch.common.lucene.search.function;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.Explanation;
|
import org.apache.lucene.search.Explanation;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
|
import org.elasticsearch.script.ScriptException;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -96,7 +97,11 @@ public class ScriptScoreFunction extends ScoreFunction {
|
||||||
script.setNextDocId(docId);
|
script.setNextDocId(docId);
|
||||||
scorer.docid = docId;
|
scorer.docid = docId;
|
||||||
scorer.score = subQueryScore;
|
scorer.score = subQueryScore;
|
||||||
return script.runAsDouble();
|
double result = script.runAsDouble();
|
||||||
|
if (Double.isNaN(result)) {
|
||||||
|
throw new ScriptException("script_score returned NaN");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.common.lucene.search.function;
|
||||||
|
|
||||||
|
import org.elasticsearch.script.AbstractFloatSearchScript;
|
||||||
|
import org.elasticsearch.script.ScriptException;
|
||||||
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
public class ScriptScoreFunctionTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests https://github.com/elasticsearch/elasticsearch/issues/2426
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testScriptScoresReturnsNaN() {
|
||||||
|
try {
|
||||||
|
ScoreFunction scoreFunction = new ScriptScoreFunction("Float.NaN", null, new FloatValueScript(Float.NaN));
|
||||||
|
scoreFunction.score(randomInt(), randomFloat());
|
||||||
|
fail("should have thrown an exception about the script_score returning NaN");
|
||||||
|
} catch (ScriptException e) {
|
||||||
|
assertThat("message contains error about script_score returning NaN: " + e.getMessage(),
|
||||||
|
e.getMessage().contains("NaN"), equalTo(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FloatValueScript extends AbstractFloatSearchScript {
|
||||||
|
|
||||||
|
private final float value;
|
||||||
|
|
||||||
|
FloatValueScript(float value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float runAsFloat() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int doc) {
|
||||||
|
// nothing here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -169,7 +169,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
assertThat(responseWithWeights.getHits().getAt(0).getExplanation().toString(),
|
assertThat(responseWithWeights.getHits().getAt(0).getExplanation().toString(),
|
||||||
equalTo("6.0 = (MATCH) function score, product of:\n 1.0 = (MATCH) ConstantScore(text_field:value), product of:\n 1.0 = boost\n 1.0 = queryNorm\n 6.0 = (MATCH) Math.min of\n 6.0 = (MATCH) function score, score mode [multiply]\n 1.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 1.0 = (MATCH) Function for field geo_point_field:\n 1.0 = exp(-0.5*pow(MIN of: [Math.max(arcDistance([10.0, 20.0](=doc value),[10.0, 20.0](=origin)) - 0.0(=offset), 0)],2.0)/7.213475204444817E11)\n 2.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 2.0 = (MATCH) product of:\n 1.0 = field value function: ln(doc['double_field'].value * factor=1.0)\n 2.0 = weight\n 3.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 3.0 = (MATCH) product of:\n 1.0 = script score function, computed with script:\"_index['text_field']['value'].tf()\n 3.0 = weight\n 3.4028235E38 = maxBoost\n 1.0 = queryBoost\n")
|
equalTo("6.0 = (MATCH) function score, product of:\n 1.0 = (MATCH) ConstantScore(text_field:value), product of:\n 1.0 = boost\n 1.0 = queryNorm\n 6.0 = (MATCH) Math.min of\n 6.0 = (MATCH) function score, score mode [multiply]\n 1.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 1.0 = (MATCH) Function for field geo_point_field:\n 1.0 = exp(-0.5*pow(MIN of: [Math.max(arcDistance([10.0, 20.0](=doc value),[10.0, 20.0](=origin)) - 0.0(=offset), 0)],2.0)/7.213475204444817E11)\n 2.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 2.0 = (MATCH) product of:\n 1.0 = field value function: ln(doc['double_field'].value * factor=1.0)\n 2.0 = weight\n 3.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 3.0 = (MATCH) product of:\n 1.0 = script score function, computed with script:\"_index['text_field']['value'].tf()\n 3.0 = weight\n 3.4028235E38 = maxBoost\n 1.0 = queryBoost\n")
|
||||||
);
|
);
|
||||||
responseWithWeights = client().search(
|
responseWithWeights = client().search(
|
||||||
searchRequest().source(
|
searchRequest().source(
|
||||||
searchSource().query(
|
searchSource().query(
|
||||||
|
|
Loading…
Reference in New Issue