Allow scripts to expose whether they use the `_score`.

This commit adds a new API to allow scripts to say whether they need scores.
In practice, only the `expression` script engine makes use of it correctly,
other engines just return `true` since they can't predict whether they'll
need scores. This should make scripted aggregations and `function_query`
faster as we'll now be able to pass needsScores=false to Query.createWeight.
This commit is contained in:
Adrien Grand 2015-08-06 17:18:56 +02:00
parent 8590fa49a6
commit b16e2d95af
27 changed files with 200 additions and 14 deletions

View File

@ -128,9 +128,7 @@ public class ScriptScoreFunction extends ScoreFunction {
@Override
public boolean needsScores() {
// Scripts might use _score so we return true here
// TODO: Make scripts able to tell us whether they use scores
return true;
return script.needsScores();
}
@Override

View File

@ -86,6 +86,10 @@ public class NativeScriptEngineService extends AbstractComponent implements Scri
script.setLookup(lookup.getLeafSearchLookup(context));
return script;
}
@Override
public boolean needsScores() {
return scriptFactory.needsScores();
}
};
}

View File

@ -41,4 +41,11 @@ public interface NativeScriptFactory {
* @param params The parameters passed to the script. Can be <tt>null</tt>.
*/
ExecutableScript newScript(@Nullable Map<String, Object> params);
/**
* Indicates if document scores may be needed by the produced scripts.
*
* @return {@code true} if scores are needed.
*/
boolean needsScores();
}

View File

@ -29,4 +29,11 @@ public interface SearchScript {
LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException;
/**
* Indicates if document scores may be needed by this {@link SearchScript}.
*
* @return {@code true} if scores are needed.
*/
boolean needsScores();
}

View File

@ -112,7 +112,6 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
for (String variable : expr.variables) {
if (variable.equals("_score")) {
bindings.add(new SortField("_score", SortField.Type.SCORE));
} else if (variable.equals("_value")) {
specialValue = new ReplaceableConstValueSource();
bindings.add("_value", specialValue);
@ -173,7 +172,8 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
}
}
return new ExpressionSearchScript(compiledScript, bindings, specialValue);
final boolean needsScores = expr.getSortField(bindings, false).needsScores();
return new ExpressionSearchScript(compiledScript, bindings, specialValue, needsScores);
} catch (Exception exception) {
throw new ScriptException("Error during search with " + compiledScript, exception);
}

View File

@ -46,14 +46,21 @@ class ExpressionSearchScript implements SearchScript {
final SimpleBindings bindings;
final ValueSource source;
final ReplaceableConstValueSource specialValue; // _value
final boolean needsScores;
Scorer scorer;
int docid;
ExpressionSearchScript(CompiledScript c, SimpleBindings b, ReplaceableConstValueSource v) {
ExpressionSearchScript(CompiledScript c, SimpleBindings b, ReplaceableConstValueSource v, boolean needsScores) {
compiledScript = c;
bindings = b;
source = ((Expression)compiledScript.compiled()).getValueSource(bindings);
specialValue = v;
this.needsScores = needsScores;
}
@Override
public boolean needsScores() {
return needsScores;
}
@Override

View File

@ -168,6 +168,12 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
}
return new GroovyScript(compiledScript, scriptObject, leafLookup, logger);
}
@Override
public boolean needsScores() {
// TODO: can we reliably know if a groovy script makes use of _score
return true;
}
};
}

View File

@ -216,8 +216,7 @@ public abstract class ValuesSource {
@Override
public boolean needsScores() {
// TODO: add a way to know whether scripts are using scores
return true;
return script.needsScores();
}
}
@ -295,8 +294,7 @@ public abstract class ValuesSource {
@Override
public boolean needsScores() {
// TODO: add a way to know whether scripts are using scores
return true;
return script.needsScores();
}
@Override
@ -431,8 +429,7 @@ public abstract class ValuesSource {
@Override
public boolean needsScores() {
// TODO: add a way to know whether scripts are using scores
return true;
return script.needsScores();
}
}
@ -451,8 +448,7 @@ public abstract class ValuesSource {
@Override
public boolean needsScores() {
// TODO: add a way to know whether scripts are using scores
return true;
return script.needsScores();
}
@Override

View File

@ -34,6 +34,11 @@ public class NativeScript1 extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeScript1();
}
@Override
public boolean needsScores() {
return false;
}
}
public static final String NATIVE_SCRIPT_1 = "native_1";

View File

@ -34,6 +34,11 @@ public class NativeScript2 extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeScript2();
}
@Override
public boolean needsScores() {
return false;
}
}
public static final String NATIVE_SCRIPT_2 = "native_2";

View File

@ -34,6 +34,11 @@ public class NativeScript3 extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeScript3();
}
@Override
public boolean needsScores() {
return false;
}
}
public static final String NATIVE_SCRIPT_3 = "native_3";

View File

@ -34,6 +34,11 @@ public class NativeScript4 extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeScript4();
}
@Override
public boolean needsScores() {
return false;
}
}
public static final String NATIVE_SCRIPT_4 = "native_4";

View File

@ -36,6 +36,11 @@ public class NativeConstantForLoopScoreScript extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeConstantForLoopScoreScript(params);
}
@Override
public boolean needsScores() {
return false;
}
}
private NativeConstantForLoopScoreScript(Map<String, Object> params) {

View File

@ -36,6 +36,11 @@ public class NativeConstantScoreScript extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeConstantScoreScript();
}
@Override
public boolean needsScores() {
return false;
}
}
private NativeConstantScoreScript() {

View File

@ -42,6 +42,11 @@ public class NativeNaiveTFIDFScoreScript extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeNaiveTFIDFScoreScript(params);
}
@Override
public boolean needsScores() {
return false;
}
}
private NativeNaiveTFIDFScoreScript(Map<String, Object> params) {

View File

@ -44,6 +44,11 @@ public class NativePayloadSumNoRecordScoreScript extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativePayloadSumNoRecordScoreScript(params);
}
@Override
public boolean needsScores() {
return false;
}
}
private NativePayloadSumNoRecordScoreScript(Map<String, Object> params) {

View File

@ -44,6 +44,11 @@ public class NativePayloadSumScoreScript extends AbstractSearchScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativePayloadSumScoreScript(params);
}
@Override
public boolean needsScores() {
return false;
}
}
private NativePayloadSumScoreScript(Map<String, Object> params) {

View File

@ -73,5 +73,10 @@ public class ScriptScoreFunctionTests extends ESTestCase {
}
};
}
@Override
public boolean needsScores() {
return false;
}
}
}

View File

@ -97,6 +97,11 @@ public class NativeScriptTests extends ESTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new MyScript();
}
@Override
public boolean needsScores() {
return false;
}
}
static class MyScript extends AbstractExecutableScript {

View File

@ -81,6 +81,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new IntScript();
}
@Override
public boolean needsScores() {
return false;
}
}
static class IntScript extends AbstractSearchScript {
@ -95,6 +100,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new LongScript();
}
@Override
public boolean needsScores() {
return false;
}
}
static class LongScript extends AbstractSearchScript {
@ -109,6 +119,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new FloatScript();
}
@Override
public boolean needsScores() {
return false;
}
}
static class FloatScript extends AbstractSearchScript {
@ -123,6 +138,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new DoubleScript();
}
@Override
public boolean needsScores() {
return false;
}
}
static class DoubleScript extends AbstractSearchScript {

View File

@ -0,0 +1,57 @@
/*
* 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.script.expression;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESSingleNodeTestCase;
import java.util.Collections;
public class ExpressionScriptTests extends ESSingleNodeTestCase {
public void testNeedsScores() {
IndexService index = createIndex("test", Settings.EMPTY, "type", "d", "type=double");
ExpressionScriptEngineService service = new ExpressionScriptEngineService(Settings.EMPTY);
SearchLookup lookup = new SearchLookup(index.mapperService(), index.fieldData(), null);
Object compiled = service.compile("1.2");
SearchScript ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "expression", compiled), lookup, Collections.<String, Object>emptyMap());
assertFalse(ss.needsScores());
compiled = service.compile("doc['d'].value");
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "expression", compiled), lookup, Collections.<String, Object>emptyMap());
assertFalse(ss.needsScores());
compiled = service.compile("1/_score");
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "expression", compiled), lookup, Collections.<String, Object>emptyMap());
assertTrue(ss.needsScores());
compiled = service.compile("doc['d'].value * _score");
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "expression", compiled), lookup, Collections.<String, Object>emptyMap());
assertTrue(ss.needsScores());
}
}

View File

@ -35,6 +35,11 @@ public class NativeSignificanceScoreScriptNoParams extends TestScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeSignificanceScoreScriptNoParams();
}
@Override
public boolean needsScores() {
return false;
}
}
private NativeSignificanceScoreScriptNoParams() {

View File

@ -36,6 +36,11 @@ public class NativeSignificanceScoreScriptWithParams extends TestScript {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new NativeSignificanceScoreScriptWithParams(params);
}
@Override
public boolean needsScores() {
return false;
}
}
private NativeSignificanceScoreScriptWithParams(Map<String, Object> params) {

View File

@ -102,6 +102,10 @@ public class ExplainableScriptIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new MyScript();
}
@Override
public boolean needsScores() {
return true;
}
}
static class MyScript extends AbstractDoubleSearchScript implements ExplainableSearchScript, ExecutableScript {

View File

@ -74,6 +74,10 @@ public class UpdateByNativeScriptIT extends ESIntegTestCase {
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new CustomScript(params);
}
@Override
public boolean needsScores() {
return false;
}
}
static class CustomScript extends AbstractExecutableScript {

View File

@ -150,6 +150,12 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements
return new JavaScriptSearchScript((Script) compiledScript.compiled(), scope, leafLookup);
}
@Override
public boolean needsScores() {
// TODO: can we reliably know if a javascript script makes use of _score
return true;
}
};
} finally {
Context.exit();

View File

@ -90,6 +90,11 @@ public class PythonScriptEngineService extends AbstractComponent implements Scri
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new PythonSearchScript((PyCode) compiledScript.compiled(), vars, leafLookup);
}
@Override
public boolean needsScores() {
// TODO: can we reliably know if a python script makes use of _score
return true;
}
};
}