special access to doc

This commit is contained in:
Robert Muir 2016-05-10 23:43:57 -04:00
parent abb015bcb9
commit 389ef462c4
10 changed files with 57 additions and 23 deletions

View File

@ -93,9 +93,22 @@ class Analyzer extends PainlessParserBaseVisitor<Void> {
utility.incrementScope();
utility.addVariable(null, "#this", definition.execType);
//
// reserved words parameters.
//
// input map of variables passed to the script. TODO: rename to 'params' since that will be its use
metadata.inputValueSlot = utility.addVariable(null, "input", definition.smapType).slot;
// scorer parameter passed to the script. internal use only.
metadata.scorerValueSlot = utility.addVariable(null, "#scorer", definition.objectType).slot;
// doc parameter passed to the script.
// TODO: currently working as a def type, should be smapType...
metadata.docValueSlot = utility.addVariable(null, "doc", definition.defType).slot;
//
// reserved words implemented as local variables
//
// loop counter to catch runaway scripts. internal use only.
metadata.loopCounterSlot = utility.addVariable(null, "#loop", definition.intType).slot;
// document's score as a read-only float.
metadata.scoreValueSlot = utility.addVariable(null, "_score", definition.floatType).slot;
metadata.createStatementMetadata(metadata.root);

View File

@ -449,11 +449,15 @@ class AnalyzerExternal {
}
// special cases: reserved words
if ("_score".equals(id)) {
if ("_score".equals(id) || "doc".equals(id)) {
// read-only: don't allow stores
if (parentemd.storeExpr != null) {
throw new IllegalArgumentException(AnalyzerUtility.error(ctx) + "Variable [" + id + "] is read-only.");
}
}
// track if the _score value is ever used, we will invoke Scorer.score() only once if so.
if ("_score".equals(id)) {
metadata.scoreValueUsed = true;
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.search.lookup.LeafDocLookup;
import java.util.Map;
@ -48,5 +49,5 @@ public abstract class Executable {
return definition;
}
public abstract Object execute(Map<String, Object> input, Scorer scorer);
public abstract Object execute(Map<String, Object> input, Scorer scorer, LeafDocLookup doc);
}

View File

@ -433,6 +433,12 @@ class Metadata {
* variable slots at the completion of analysis if _score is not used.
*/
boolean scoreValueUsed = false;
/**
* Used to determine what slot the doc variable is stored in. This is used in the {@link Writer} whenever
* the doc variable is accessed.
*/
int docValueSlot = -1;
/**
* Maps the relevant ANTLR node to its metadata.

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.search.lookup.LeafDocLookup;
import org.elasticsearch.search.lookup.LeafSearchLookup;
import java.util.HashMap;
@ -46,6 +47,11 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
* The lookup is used to access search field values at run-time.
*/
private final LeafSearchLookup lookup;
/**
* the 'doc' object accessed by the script, if available.
*/
private final LeafDocLookup doc;
/**
* Current scorer being used
@ -70,6 +76,9 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
if (lookup != null) {
variables.putAll(lookup.asMap());
doc = lookup.doc();
} else {
doc = null;
}
}
@ -89,7 +98,7 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
*/
@Override
public Object run() {
return executable.execute(variables, scorer);
return executable.execute(variables, scorer, doc);
}
/**

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.search.lookup.LeafDocLookup;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@ -37,7 +38,7 @@ class WriterConstants {
final static Type CLASS_TYPE = Type.getType("L" + CLASS_NAME.replace(".", "/") + ";");
final static Method CONSTRUCTOR = getAsmMethod(void.class, "<init>", Definition.class, String.class, String.class);
final static Method EXECUTE = getAsmMethod(Object.class, "execute", Map.class, Scorer.class);
final static Method EXECUTE = getAsmMethod(Object.class, "execute", Map.class, Scorer.class, LeafDocLookup.class);
final static Type PAINLESS_ERROR_TYPE = Type.getType(PainlessError.class);

View File

@ -46,7 +46,7 @@ public class NeedsScoreTests extends ESSingleNodeTestCase {
lookup, Collections.<String, Object>emptyMap());
assertFalse(ss.needsScores());
compiled = service.compile("input.doc['d'].value", Collections.emptyMap());
compiled = service.compile("doc['d'].value", Collections.emptyMap());
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled),
lookup, Collections.<String, Object>emptyMap());
assertFalse(ss.needsScores());
@ -56,7 +56,7 @@ public class NeedsScoreTests extends ESSingleNodeTestCase {
lookup, Collections.<String, Object>emptyMap());
assertTrue(ss.needsScores());
compiled = service.compile("input.doc['d'].value * _score", Collections.emptyMap());
compiled = service.compile("doc['d'].value * _score", Collections.emptyMap());
ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled),
lookup, Collections.<String, Object>emptyMap());
assertTrue(ss.needsScores());

View File

@ -5,7 +5,7 @@
put_script:
id: "1"
lang: "painless"
body: { "script": "_score * input.doc[\"myParent.weight\"].value" }
body: { "script": "_score * doc[\"myParent.weight\"].value" }
- match: { acknowledged: true }
- do:
@ -15,7 +15,7 @@
- match: { found: true }
- match: { lang: painless }
- match: { _id: "1" }
- match: { "script": "_score * input.doc[\"myParent.weight\"].value" }
- match: { "script": "_score * doc[\"myParent.weight\"].value" }
- do:
catch: missing
@ -44,11 +44,11 @@
put_script:
id: "1"
lang: "painless"
body: { "script": "_score * foo bar + input.doc[\"myParent.weight\"].value" }
body: { "script": "_score * foo bar + doc[\"myParent.weight\"].value" }
- do:
catch: /Unable.to.parse.*/
put_script:
id: "1"
lang: "painless"
body: { "script": "_score * foo bar + input.doc[\"myParent.weight\"].value" }
body: { "script": "_score * foo bar + doc[\"myParent.weight\"].value" }

View File

@ -28,7 +28,7 @@ setup:
script_fields:
bar:
script:
inline: "input.doc['foo'].value + input.x;"
inline: "doc['foo'].value + input.x;"
lang: painless
params:
x: "bbb"

View File

@ -29,12 +29,12 @@
query:
script:
script:
inline: "input.doc['num1'].value > 1;"
inline: "doc['num1'].value > 1;"
lang: painless
script_fields:
sNum1:
script:
inline: "input.doc['num1'].value;"
inline: "doc['num1'].value;"
lang: painless
sort:
num1:
@ -51,7 +51,7 @@
query:
script:
script:
inline: "input.doc['num1'].value > input.param1;"
inline: "doc['num1'].value > input.param1;"
lang: painless
params:
param1: 1
@ -59,7 +59,7 @@
script_fields:
sNum1:
script:
inline: "return input.doc['num1'].value;"
inline: "return doc['num1'].value;"
lang: painless
sort:
num1:
@ -76,7 +76,7 @@
query:
script:
script:
inline: "input.doc['num1'].value > input.param1;"
inline: "doc['num1'].value > input.param1;"
lang: painless
params:
param1: -1
@ -84,7 +84,7 @@
script_fields:
sNum1:
script:
inline: "input.doc['num1'].value;"
inline: "doc['num1'].value;"
lang: painless
sort:
num1:
@ -126,7 +126,7 @@
"script_score": {
"script": {
"lang": "painless",
"inline": "input.doc['num1'].value"
"inline": "doc['num1'].value"
}
}
}]
@ -148,7 +148,7 @@
"script_score": {
"script": {
"lang": "painless",
"inline": "-input.doc['num1'].value"
"inline": "-doc['num1'].value"
}
}
}]
@ -170,7 +170,7 @@
"script_score": {
"script": {
"lang": "painless",
"inline": "Math.pow(input.doc['num1'].value, 2)"
"inline": "Math.pow(doc['num1'].value, 2)"
}
}
}]
@ -192,7 +192,7 @@
"script_score": {
"script": {
"lang": "painless",
"inline": "Math.max(input.doc['num1'].value, 1)"
"inline": "Math.max(doc['num1'].value, 1)"
}
}
}]
@ -214,7 +214,7 @@
"script_score": {
"script": {
"lang": "painless",
"inline": "input.doc['num1'].value * _score"
"inline": "doc['num1'].value * _score"
}
}
}]
@ -357,7 +357,7 @@
script_fields:
foobar:
script:
inline: "input.doc['f'].values.size()"
inline: "doc['f'].values.size()"
lang: painless