special access to doc
This commit is contained in:
parent
abb015bcb9
commit
389ef462c4
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -434,6 +434,12 @@ class Metadata {
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
@ -47,6 +48,11 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
|
|||
*/
|
||||
private final LeafSearchLookup lookup;
|
||||
|
||||
/**
|
||||
* the 'doc' object accessed by the script, if available.
|
||||
*/
|
||||
private final LeafDocLookup doc;
|
||||
|
||||
/**
|
||||
* Current scorer being used
|
||||
* @see #setScorer(Scorer)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue