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.index.AtomicReaderContext;
|
||||||
import org.apache.lucene.search.Explanation;
|
import org.apache.lucene.search.Explanation;
|
||||||
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.elasticsearch.script.ExplainableSearchScript;
|
import org.elasticsearch.script.ExplainableSearchScript;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ScriptScoreFunction extends ScoreFunction {
|
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 String sScript;
|
||||||
|
|
||||||
private final Map<String, Object> params;
|
private final Map<String, Object> params;
|
||||||
|
|
||||||
|
private final CannedScorer scorer;
|
||||||
|
|
||||||
private final SearchScript script;
|
private final SearchScript script;
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,6 +83,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
||||||
this.sScript = sScript;
|
this.sScript = sScript;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.script = script;
|
this.script = script;
|
||||||
|
this.scorer = new CannedScorer();
|
||||||
|
script.setScorer(scorer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,7 +95,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
||||||
@Override
|
@Override
|
||||||
public double score(int docId, float subQueryScore) {
|
public double score(int docId, float subQueryScore) {
|
||||||
script.setNextDocId(docId);
|
script.setNextDocId(docId);
|
||||||
script.setNextScore(subQueryScore);
|
scorer.docid = docId;
|
||||||
|
scorer.score = subQueryScore;
|
||||||
return script.runAsDouble();
|
return script.runAsDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +105,8 @@ public class ScriptScoreFunction extends ScoreFunction {
|
||||||
Explanation exp;
|
Explanation exp;
|
||||||
if (script instanceof ExplainableSearchScript) {
|
if (script instanceof ExplainableSearchScript) {
|
||||||
script.setNextDocId(docId);
|
script.setNextDocId(docId);
|
||||||
script.setNextScore(subQueryExpl.getValue());
|
scorer.docid = docId;
|
||||||
|
scorer.score = subQueryExpl.getValue();
|
||||||
exp = ((ExplainableSearchScript) script).explain(subQueryExpl);
|
exp = ((ExplainableSearchScript) script).explain(subQueryExpl);
|
||||||
} else {
|
} else {
|
||||||
double score = score(docId, subQueryExpl.getValue());
|
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.SearchLookup;
|
||||||
import org.elasticsearch.search.lookup.SourceLookup;
|
import org.elasticsearch.search.lookup.SourceLookup;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,16 +45,6 @@ public abstract class AbstractSearchScript extends AbstractExecutableScript impl
|
||||||
|
|
||||||
private SearchLookup lookup;
|
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
|
* Returns the doc lookup allowing to access field data (cached) values as well as the current document score
|
||||||
* (where applicable).
|
* (where applicable).
|
||||||
|
@ -128,11 +119,6 @@ public abstract class AbstractSearchScript extends AbstractExecutableScript impl
|
||||||
lookup.source().setNextSource(source);
|
lookup.source().setNextSource(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNextScore(float score) {
|
|
||||||
this.score = score;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float runAsFloat() {
|
public float runAsFloat() {
|
||||||
return ((Number) run()).floatValue();
|
return ((Number) run()).floatValue();
|
||||||
|
|
|
@ -36,8 +36,6 @@ public interface SearchScript extends ExecutableScript, ReaderContextAware, Scor
|
||||||
|
|
||||||
void setNextSource(Map<String, Object> source);
|
void setNextSource(Map<String, Object> source);
|
||||||
|
|
||||||
void setNextScore(float score);
|
|
||||||
|
|
||||||
float runAsFloat();
|
float runAsFloat();
|
||||||
|
|
||||||
long runAsLong();
|
long runAsLong();
|
||||||
|
|
|
@ -38,65 +38,25 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
class ExpressionScript implements SearchScript {
|
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 Expression expression;
|
||||||
final XSimpleBindings bindings;
|
final XSimpleBindings bindings;
|
||||||
final CannedScorer scorer;
|
|
||||||
final ValueSource source;
|
final ValueSource source;
|
||||||
final Map<String, CannedScorer> context;
|
|
||||||
final ReplaceableConstValueSource specialValue; // _value
|
final ReplaceableConstValueSource specialValue; // _value
|
||||||
|
Map<String, Scorer> context;
|
||||||
|
Scorer scorer;
|
||||||
FunctionValues values;
|
FunctionValues values;
|
||||||
|
int docid;
|
||||||
|
|
||||||
ExpressionScript(Expression e, XSimpleBindings b, ReplaceableConstValueSource v) {
|
ExpressionScript(Expression e, XSimpleBindings b, ReplaceableConstValueSource v) {
|
||||||
expression = e;
|
expression = e;
|
||||||
bindings = b;
|
bindings = b;
|
||||||
scorer = new CannedScorer();
|
context = Collections.EMPTY_MAP;
|
||||||
context = Collections.singletonMap("scorer", scorer);
|
|
||||||
source = expression.getValueSource(bindings);
|
source = expression.getValueSource(bindings);
|
||||||
specialValue = v;
|
specialValue = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
double evaluate() {
|
double evaluate() {
|
||||||
return values.doubleVal(scorer.docid);
|
return values.doubleVal(docid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,17 +76,7 @@ class ExpressionScript implements SearchScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setNextDocId(int d) {
|
public void setNextDocId(int d) {
|
||||||
scorer.docid = d;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,8 +90,8 @@ class ExpressionScript implements SearchScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer s) {
|
public void setScorer(Scorer s) {
|
||||||
// noop: The scorer isn't actually ever set. Instead setNextScore is called.
|
scorer = s;
|
||||||
// NOTE: This seems broken. Why can't we just use the scorer and get rid of setNextScore?
|
context = Collections.singletonMap("scorer", scorer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.elasticsearch.script.ExecutableScript;
|
||||||
import org.elasticsearch.script.ScriptEngineService;
|
import org.elasticsearch.script.ScriptEngineService;
|
||||||
import org.elasticsearch.script.ScriptException;
|
import org.elasticsearch.script.ScriptException;
|
||||||
import org.elasticsearch.script.SearchScript;
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
import org.elasticsearch.search.lookup.DocLookup;
|
||||||
import org.elasticsearch.search.lookup.SearchLookup;
|
import org.elasticsearch.search.lookup.SearchLookup;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -188,7 +189,6 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
||||||
private final Script script;
|
private final Script script;
|
||||||
private final SearchLookup lookup;
|
private final SearchLookup lookup;
|
||||||
private final Map<String, Object> variables;
|
private final Map<String, Object> variables;
|
||||||
private final UpdateableFloat score;
|
|
||||||
private final ESLogger logger;
|
private final ESLogger logger;
|
||||||
|
|
||||||
public GroovyScript(Script script, ESLogger logger) {
|
public GroovyScript(Script script, ESLogger logger) {
|
||||||
|
@ -200,10 +200,8 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
||||||
this.lookup = lookup;
|
this.lookup = lookup;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.variables = script.getBinding().getVariables();
|
this.variables = script.getBinding().getVariables();
|
||||||
this.score = new UpdateableFloat(0);
|
// Add the _score variable, which will access score from lookup.doc()
|
||||||
// Add the _score variable, which will be updated per-document by
|
this.variables.put("_score", new ScoreAccessor());
|
||||||
// setting .value on the UpdateableFloat instance
|
|
||||||
this.variables.put("_score", this.score);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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"})
|
@SuppressWarnings({"unchecked"})
|
||||||
@Override
|
@Override
|
||||||
public void setNextVar(String name, Object value) {
|
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
|
* so that updating the _score for the next document incurs only the
|
||||||
* overhead of setting a member variable
|
* overhead of setting a member variable
|
||||||
*/
|
*/
|
||||||
private final class UpdateableFloat extends Number {
|
private final class ScoreAccessor extends Number {
|
||||||
|
|
||||||
public float value;
|
float score() {
|
||||||
|
try {
|
||||||
public UpdateableFloat(float value) {
|
return lookup.doc().score();
|
||||||
this.value = value;
|
} catch (IOException e) {
|
||||||
|
throw new GroovyScriptExecutionException("Could not get score", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int intValue() {
|
public int intValue() {
|
||||||
return (int)value;
|
return (int)score();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long longValue() {
|
public long longValue() {
|
||||||
return (long)value;
|
return (long)score();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float floatValue() {
|
public float floatValue() {
|
||||||
return value;
|
return score();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double doubleValue() {
|
public double doubleValue() {
|
||||||
return value;
|
return score();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@ public class GroovyScriptExecutionException extends ElasticsearchException {
|
||||||
public GroovyScriptExecutionException(String message) {
|
public GroovyScriptExecutionException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
public GroovyScriptExecutionException(String message, Throwable t) {
|
||||||
|
super(message, t);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestStatus status() {
|
public RestStatus status() {
|
||||||
|
|
|
@ -90,10 +90,6 @@ public class FieldDataSourceTests extends ElasticsearchTestCase {
|
||||||
public void setNextSource(Map<String, Object> source) {
|
public void setNextSource(Map<String, Object> source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNextScore(float score) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float runAsFloat() {
|
public float runAsFloat() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -81,10 +81,6 @@ public class ScriptValuesTests extends ElasticsearchTestCase {
|
||||||
public void setNextSource(Map<String, Object> source) {
|
public void setNextSource(Map<String, Object> source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNextScore(float score) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float runAsFloat() {
|
public float runAsFloat() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
Loading…
Reference in New Issue