Scripting: Remove setNextScore in SearchScript.
While it would be nice to do this all the way up the chain (into score functions), this at least removes the weird dual setNextScore/setScorer for SearchScripts. closes #6864
This commit is contained in:
parent
ca7fa4f9ec
commit
770447ce1a
|
@ -21,17 +21,60 @@ package org.elasticsearch.common.lucene.search.function;
|
|||
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.Explanation;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
import org.elasticsearch.script.ExplainableSearchScript;
|
||||
import org.elasticsearch.script.SearchScript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class ScriptScoreFunction extends ScoreFunction {
|
||||
|
||||
static final class CannedScorer extends Scorer {
|
||||
protected int docid;
|
||||
protected float score;
|
||||
|
||||
public CannedScorer() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return docid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float score() throws IOException {
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int freq() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextDoc() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int advance(int target) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long cost() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private final String sScript;
|
||||
|
||||
private final Map<String, Object> params;
|
||||
|
||||
private final CannedScorer scorer;
|
||||
|
||||
private final SearchScript script;
|
||||
|
||||
|
||||
|
@ -40,6 +83,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
|||
this.sScript = sScript;
|
||||
this.params = params;
|
||||
this.script = script;
|
||||
this.scorer = new CannedScorer();
|
||||
script.setScorer(scorer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,7 +95,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
|||
@Override
|
||||
public double score(int docId, float subQueryScore) {
|
||||
script.setNextDocId(docId);
|
||||
script.setNextScore(subQueryScore);
|
||||
scorer.docid = docId;
|
||||
scorer.score = subQueryScore;
|
||||
return script.runAsDouble();
|
||||
}
|
||||
|
||||
|
@ -59,7 +105,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
|||
Explanation exp;
|
||||
if (script instanceof ExplainableSearchScript) {
|
||||
script.setNextDocId(docId);
|
||||
script.setNextScore(subQueryExpl.getValue());
|
||||
scorer.docid = docId;
|
||||
scorer.score = subQueryExpl.getValue();
|
||||
exp = ((ExplainableSearchScript) script).explain(subQueryExpl);
|
||||
} else {
|
||||
double score = score(docId, subQueryExpl.getValue());
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.search.lookup.FieldsLookup;
|
|||
import org.elasticsearch.search.lookup.SearchLookup;
|
||||
import org.elasticsearch.search.lookup.SourceLookup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -44,16 +45,6 @@ public abstract class AbstractSearchScript extends AbstractExecutableScript impl
|
|||
|
||||
private SearchLookup lookup;
|
||||
|
||||
private float score = Float.NaN;
|
||||
|
||||
/**
|
||||
* Returns the current score and only applicable when used as a scoring script in a custom score query!.
|
||||
* For other cases, use {@link #doc()} and get the score from it.
|
||||
*/
|
||||
protected final float score() {
|
||||
return score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the doc lookup allowing to access field data (cached) values as well as the current document score
|
||||
* (where applicable).
|
||||
|
@ -128,11 +119,6 @@ public abstract class AbstractSearchScript extends AbstractExecutableScript impl
|
|||
lookup.source().setNextSource(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextScore(float score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float runAsFloat() {
|
||||
return ((Number) run()).floatValue();
|
||||
|
|
|
@ -36,8 +36,6 @@ public interface SearchScript extends ExecutableScript, ReaderContextAware, Scor
|
|||
|
||||
void setNextSource(Map<String, Object> source);
|
||||
|
||||
void setNextScore(float score);
|
||||
|
||||
float runAsFloat();
|
||||
|
||||
long runAsLong();
|
||||
|
|
|
@ -38,65 +38,25 @@ import java.util.Map;
|
|||
*/
|
||||
class ExpressionScript implements SearchScript {
|
||||
|
||||
/** Fake scorer for a single document */
|
||||
static class CannedScorer extends Scorer {
|
||||
protected int docid;
|
||||
protected float score;
|
||||
|
||||
public CannedScorer() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return docid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float score() throws IOException {
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int freq() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextDoc() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int advance(int target) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long cost() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
final Expression expression;
|
||||
final XSimpleBindings bindings;
|
||||
final CannedScorer scorer;
|
||||
final ValueSource source;
|
||||
final Map<String, CannedScorer> context;
|
||||
final ReplaceableConstValueSource specialValue; // _value
|
||||
Map<String, Scorer> context;
|
||||
Scorer scorer;
|
||||
FunctionValues values;
|
||||
int docid;
|
||||
|
||||
ExpressionScript(Expression e, XSimpleBindings b, ReplaceableConstValueSource v) {
|
||||
expression = e;
|
||||
bindings = b;
|
||||
scorer = new CannedScorer();
|
||||
context = Collections.singletonMap("scorer", scorer);
|
||||
context = Collections.EMPTY_MAP;
|
||||
source = expression.getValueSource(bindings);
|
||||
specialValue = v;
|
||||
}
|
||||
|
||||
double evaluate() {
|
||||
return values.doubleVal(scorer.docid);
|
||||
return values.doubleVal(docid);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,17 +76,7 @@ class ExpressionScript implements SearchScript {
|
|||
|
||||
@Override
|
||||
public void setNextDocId(int d) {
|
||||
scorer.docid = d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextScore(float score) {
|
||||
// TODO: fix this API to remove setNextScore and just use a Scorer
|
||||
// Expressions know if they use the score or not, and should be able to pull from the scorer only
|
||||
// if they need it. Right now, score can only be used within a ScriptScoreFunction. But there shouldn't
|
||||
// be any reason a script values or aggregation can't use the score. It is also possible
|
||||
// these layers are preventing inlining of scoring into expressions.
|
||||
scorer.score = score;
|
||||
docid = d;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,8 +90,8 @@ class ExpressionScript implements SearchScript {
|
|||
|
||||
@Override
|
||||
public void setScorer(Scorer s) {
|
||||
// noop: The scorer isn't actually ever set. Instead setNextScore is called.
|
||||
// NOTE: This seems broken. Why can't we just use the scorer and get rid of setNextScore?
|
||||
scorer = s;
|
||||
context = Collections.singletonMap("scorer", scorer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.elasticsearch.script.ExecutableScript;
|
|||
import org.elasticsearch.script.ScriptEngineService;
|
||||
import org.elasticsearch.script.ScriptException;
|
||||
import org.elasticsearch.script.SearchScript;
|
||||
import org.elasticsearch.search.lookup.DocLookup;
|
||||
import org.elasticsearch.search.lookup.SearchLookup;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -188,7 +189,6 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
private final Script script;
|
||||
private final SearchLookup lookup;
|
||||
private final Map<String, Object> variables;
|
||||
private final UpdateableFloat score;
|
||||
private final ESLogger logger;
|
||||
|
||||
public GroovyScript(Script script, ESLogger logger) {
|
||||
|
@ -200,10 +200,8 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
this.lookup = lookup;
|
||||
this.logger = logger;
|
||||
this.variables = script.getBinding().getVariables();
|
||||
this.score = new UpdateableFloat(0);
|
||||
// Add the _score variable, which will be updated per-document by
|
||||
// setting .value on the UpdateableFloat instance
|
||||
this.variables.put("_score", this.score);
|
||||
// Add the _score variable, which will access score from lookup.doc()
|
||||
this.variables.put("_score", new ScoreAccessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,12 +225,6 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override
|
||||
public void setNextScore(float score) {
|
||||
this.score.value = score;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override
|
||||
public void setNextVar(String name, Object value) {
|
||||
|
@ -284,32 +276,34 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
|||
* so that updating the _score for the next document incurs only the
|
||||
* overhead of setting a member variable
|
||||
*/
|
||||
private final class UpdateableFloat extends Number {
|
||||
private final class ScoreAccessor extends Number {
|
||||
|
||||
public float value;
|
||||
|
||||
public UpdateableFloat(float value) {
|
||||
this.value = value;
|
||||
float score() {
|
||||
try {
|
||||
return lookup.doc().score();
|
||||
} catch (IOException e) {
|
||||
throw new GroovyScriptExecutionException("Could not get score", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int)value;
|
||||
return (int)score();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long)value;
|
||||
return (long)score();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
return score();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
return score();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ public class GroovyScriptExecutionException extends ElasticsearchException {
|
|||
public GroovyScriptExecutionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
public GroovyScriptExecutionException(String message, Throwable t) {
|
||||
super(message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestStatus status() {
|
||||
|
|
|
@ -90,10 +90,6 @@ public class FieldDataSourceTests extends ElasticsearchTestCase {
|
|||
public void setNextSource(Map<String, Object> source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextScore(float score) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float runAsFloat() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -81,10 +81,6 @@ public class ScriptValuesTests extends ElasticsearchTestCase {
|
|||
public void setNextSource(Map<String, Object> source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextScore(float score) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float runAsFloat() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
Loading…
Reference in New Issue