From 6b53dadcf91b74bd49e9f97f55498c832590952b Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Mon, 9 Oct 2017 17:02:21 -0700 Subject: [PATCH] Scripting: Fix expressions to temporarily support filter scripts (#26824) This commit adds a hack converting 0.0 to false and non-zero to true for expressions operating under a filter context. closes #26429 --- .../expression/ExpressionScriptEngine.java | 25 +++++++++++++++++++ .../expression/MoreExpressionTests.java | 15 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java index 17dc2740ee4..b50eb788c6f 100644 --- a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java +++ b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java @@ -38,6 +38,7 @@ import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ClassPermission; import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.FilterScript; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptException; @@ -107,6 +108,9 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE } else if (context.instanceClazz.equals(ExecutableScript.class)) { ExecutableScript.Factory factory = (p) -> new ExpressionExecutableScript(expr, p); return context.factoryClazz.cast(factory); + } else if (context.instanceClazz.equals(FilterScript.class)) { + FilterScript.Factory factory = (p, lookup) -> newFilterScript(expr, lookup, p); + return context.factoryClazz.cast(factory); } throw new IllegalArgumentException("expression engine does not know how to handle script context [" + context.name + "]"); } @@ -236,6 +240,27 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE return new ExpressionSearchScript(expr, bindings, specialValue, needsScores); } + /** + * This is a hack for filter scripts, which must return booleans instead of doubles as expression do. + * See https://github.com/elastic/elasticsearch/issues/26429. + */ + private FilterScript.LeafFactory newFilterScript(Expression expr, SearchLookup lookup, @Nullable Map vars) { + SearchScript.LeafFactory searchLeafFactory = newSearchScript(expr, lookup, vars); + return ctx -> { + SearchScript script = searchLeafFactory.newInstance(ctx); + return new FilterScript(vars, lookup, ctx) { + @Override + public boolean execute() { + return script.runAsDouble() != 0.0; + } + @Override + public void setDocument(int docid) { + script.setDocument(docid); + } + }; + }; + } + /** * converts a ParseException at compile-time or link-time to a ScriptException */ diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java index d8d09ffba79..9a91fccf4ad 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java @@ -700,4 +700,19 @@ public class MoreExpressionTests extends ESIntegTestCase { assertEquals(2.0D, rsp.getHits().getAt(1).field("foo").getValue(), 1.0D); assertEquals(2.0D, rsp.getHits().getAt(2).field("foo").getValue(), 1.0D); } + + public void testFilterScript() throws Exception { + createIndex("test"); + ensureGreen("test"); + indexRandom(true, + client().prepareIndex("test", "doc", "1").setSource("foo", 1.0), + client().prepareIndex("test", "doc", "2").setSource("foo", 0.0)); + SearchRequestBuilder builder = buildRequest("doc['foo'].value"); + Script script = new Script(ScriptType.INLINE, "expression", "doc['foo'].value", Collections.emptyMap()); + builder.setQuery(QueryBuilders.boolQuery().filter(QueryBuilders.scriptQuery(script))); + SearchResponse rsp = builder.get(); + assertSearchResponse(rsp); + assertEquals(1, rsp.getHits().getTotalHits()); + assertEquals(1.0D, rsp.getHits().getAt(0).field("foo").getValue(), 0.0D); + } }