diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java index 56a3647557cd9..01c605e4c4dea 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java @@ -50,6 +50,7 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexService; +import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.ParsedDocument; import org.elasticsearch.index.mapper.SourceToParse; import org.elasticsearch.index.query.AbstractQueryBuilder; @@ -60,12 +61,19 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.script.BooleanFieldScript; +import org.elasticsearch.script.DateFieldScript; +import org.elasticsearch.script.DoubleFieldScript; import org.elasticsearch.script.FilterScript; +import org.elasticsearch.script.GeoPointFieldScript; +import org.elasticsearch.script.IpFieldScript; +import org.elasticsearch.script.LongFieldScript; import org.elasticsearch.script.ScoreScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptType; +import org.elasticsearch.script.StringFieldScript; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; @@ -105,7 +113,15 @@ public static class Request extends SingleShardRequest implements ToXCo static final Map> SUPPORTED_CONTEXTS = Map.of( "painless_test", PainlessTestScript.CONTEXT, "filter", FilterScript.CONTEXT, - "score", ScoreScript.CONTEXT); + "score", ScoreScript.CONTEXT, + "boolean_field", BooleanFieldScript.CONTEXT, + "date_field", DateFieldScript.CONTEXT, + "double_field", DoubleFieldScript.CONTEXT, + "geo_point_field", GeoPointFieldScript.CONTEXT, + "ip_field", IpFieldScript.CONTEXT, + "long_field", LongFieldScript.CONTEXT, + "string_field", StringFieldScript.CONTEXT) + ; static ScriptContext fromScriptContextName(String name) { ScriptContext scriptContext = SUPPORTED_CONTEXTS.get(name); @@ -492,7 +508,7 @@ static Response innerShardOperation(Request request, ScriptService scriptService return prepareRamIndex(request, (context, leafReaderContext) -> { FilterScript.Factory factory = scriptService.compile(request.script, FilterScript.CONTEXT); FilterScript.LeafFactory leafFactory = - factory.newFactory(request.getScript().getParams(), context.lookup()); + factory.newFactory(request.getScript().getParams(), context.lookup()); FilterScript filterScript = leafFactory.newInstance(leafReaderContext); filterScript.setDocument(0); boolean result = filterScript.execute(); @@ -502,7 +518,7 @@ static Response innerShardOperation(Request request, ScriptService scriptService return prepareRamIndex(request, (context, leafReaderContext) -> { ScoreScript.Factory factory = scriptService.compile(request.script, ScoreScript.CONTEXT); ScoreScript.LeafFactory leafFactory = - factory.newFactory(request.getScript().getParams(), context.lookup()); + factory.newFactory(request.getScript().getParams(), context.lookup()); ScoreScript scoreScript = leafFactory.newInstance(leafReaderContext); scoreScript.setDocument(0); @@ -521,6 +537,69 @@ static Response innerShardOperation(Request request, ScriptService scriptService double result = scoreScript.execute(null); return new Response(result); }, indexService); + } else if (scriptContext == BooleanFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + BooleanFieldScript.Factory factory = scriptService.compile(request.script, BooleanFieldScript.CONTEXT); + BooleanFieldScript.LeafFactory leafFactory = + factory.newFactory("boolean_field", request.getScript().getParams(), context.lookup()); + BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext); + booleanFieldScript.runForDoc(0); + return new Response(booleanFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == DateFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + DateFieldScript.Factory factory = scriptService.compile(request.script, DateFieldScript.CONTEXT); + DateFieldScript.LeafFactory leafFactory = factory.newFactory("date_field", + request.getScript().getParams(), context.lookup(), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); + DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext); + dateFieldScript.runForDoc(0); + return new Response(dateFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == DoubleFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + DoubleFieldScript.Factory factory = scriptService.compile(request.script, DoubleFieldScript.CONTEXT); + DoubleFieldScript.LeafFactory leafFactory = + factory.newFactory("double_field", request.getScript().getParams(), context.lookup()); + DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext); + doubleFieldScript.runForDoc(0); + return new Response(doubleFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == GeoPointFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + GeoPointFieldScript.Factory factory = scriptService.compile(request.script, GeoPointFieldScript.CONTEXT); + GeoPointFieldScript.LeafFactory leafFactory = + factory.newFactory("geo_point_field", request.getScript().getParams(), context.lookup()); + GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext); + geoPointFieldScript.runForDoc(0); + return new Response(geoPointFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == IpFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + IpFieldScript.Factory factory = scriptService.compile(request.script, IpFieldScript.CONTEXT); + IpFieldScript.LeafFactory leafFactory = + factory.newFactory("ip_field", request.getScript().getParams(), context.lookup()); + IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext); + ipFieldScript.runForDoc(0); + return new Response(ipFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == LongFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + LongFieldScript.Factory factory = scriptService.compile(request.script, LongFieldScript.CONTEXT); + LongFieldScript.LeafFactory leafFactory = + factory.newFactory("long_field", request.getScript().getParams(), context.lookup()); + LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext); + longFieldScript.runForDoc(0); + return new Response(longFieldScript.asDocValues()); + }, indexService); + } else if (scriptContext == StringFieldScript.CONTEXT) { + return prepareRamIndex(request, (context, leafReaderContext) -> { + StringFieldScript.Factory factory = scriptService.compile(request.script, StringFieldScript.CONTEXT); + StringFieldScript.LeafFactory leafFactory = + factory.newFactory("string_field", request.getScript().getParams(), context.lookup()); + StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext); + stringFieldScript.resultsForDoc(0); + return new Response(stringFieldScript.asDocValues()); + }, indexService); } else { throw new UnsupportedOperationException("unsupported context [" + scriptContext.name + "]"); } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java index b0a395e842a5d..d410fbd4c5468 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java @@ -7,10 +7,12 @@ */ package org.elasticsearch.painless.action; +import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.IndexService; +import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.painless.PainlessPlugin; import org.elasticsearch.painless.action.PainlessExecuteAction.Request; @@ -28,6 +30,7 @@ import java.util.HashMap; import java.util.Map; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.elasticsearch.painless.action.PainlessExecuteAction.TransportAction.innerShardOperation; import static org.hamcrest.Matchers.equalTo; @@ -100,6 +103,168 @@ public void testScoreExecutionContext() throws IOException { assertThat(response.getResult(), equalTo(0.93D)); } + public void testBooleanFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "rank", "type=long", "text", "type=text"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"rank\": 4.0, \"text\": \"quick brown fox\"}"), new MatchQueryBuilder("text", "fox")); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['rank'].value < params.max_rank)", singletonMap("max_rank", 5.0)), "boolean_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((boolean[])response.getResult(), new boolean[] {true}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(false); emit(true); emit (false);", emptyMap()), "boolean_field", + contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((boolean[])response.getResult(), new boolean[] {false, false, true}); + } + + public void testDateFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "test_date", "type=date"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"test_date\":\"2015-01-01T12:10:30Z\"}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['test_date'].value.toInstant().toEpochMilli())", emptyMap()), "date_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {1420114230000L}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(ZonedDateTime.parse(\"2021-01-01T00:00:00Z\").toInstant().toEpochMilli());\n" + + "emit(ZonedDateTime.parse(\"1942-05-31T15:16:17Z\").toInstant().toEpochMilli());\n" + + "emit(ZonedDateTime.parse(\"2035-10-13T10:54:19Z\").toInstant().toEpochMilli());", + emptyMap()), "date_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {-870597823000L, 1609459200000L, 2075885659000L}); + } + + public void testDoubleFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "rank", "type=long", "text", "type=text"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"rank\": 4.0, \"text\": \"quick brown fox\"}"), new MatchQueryBuilder("text", "fox")); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['rank'].value); emit(Math.log(doc['rank'].value))", emptyMap()), "double_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((double[])response.getResult(), new double[] {Math.log(4.0), 4.0}, 0.00001); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(3.1); emit(2.29); emit(-12.47); emit(-12.46); emit(Double.MAX_VALUE); emit(0.0);", + emptyMap()), "double_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((double[])response.getResult(), new double[] {-12.47, -12.46, 0.0, 2.29, 3.1, Double.MAX_VALUE}, 0.00001); + } + + public void testGeoPointFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "test_point", "type=geo_point"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"test_point\":\"30.0,40.0\"}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['test_point'].value.lat + 1.0, doc['test_point'].value.lon - 1.0)", emptyMap()), + "geo_point_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {3176939252927413179L}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(78.96, 12.12); emit(13.45, 56.78);", + emptyMap()), "geo_point_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {1378381707499043786L, 8091971733044486384L}); + } + + public void testIpFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "test_ip", "type=ip"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"test_ip\":\"192.168.1.254\"}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['test_ip'].value);", emptyMap()), + "ip_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((BytesRef[])response.getResult(), + new BytesRef[] {new BytesRef(new byte[] {0,0,0,0,0,0,0,0,0,0,(byte)255,(byte)255,(byte)192,(byte)168,1,(byte)254})}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(\"192.168.0.1\"); emit(\"127.0.0.1\"); emit(\"255.255.255.255\"); emit(\"0.0.0.0\");", + emptyMap()), "ip_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((BytesRef[])response.getResult(), new BytesRef[] { + new BytesRef(new byte[] {0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0}), + new BytesRef(new byte[] {0,0,0,0,0,0,0,0,0,0,-1,-1,127,0,0,1}), + new BytesRef(new byte[] {0,0,0,0,0,0,0,0,0,0,-1,-1,-64,-88,0,1}), + new BytesRef(new byte[] {0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1})}); + } + + public void testLongFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "test_point", "type=geo_point"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"test_point\":\"30.2,40.2\"}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit((long)doc['test_point'].value.lat); emit((long)doc['test_point'].value.lon);", emptyMap()), + "long_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {30, 40}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(3L); emit(1L); emit(20000000000L); emit(10L); emit(-1000L); emit(0L);", + emptyMap()), "long_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((long[])response.getResult(), new long[] {-1000L, 0L, 1L, 3L, 10L, 20000000000L}); + } + + public void testStringFieldExecutionContext() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "test_point", "type=geo_point"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", + new BytesArray("{\"test_point\":\"30.2,40.2\"}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(doc['test_point'].value.lat.toString().substring(0, 5)); " + + "emit(doc['test_point'].value.lon.toString().substring(0, 5));", emptyMap()), + "string_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((String[])response.getResult(), new String[] {"30.19", "40.19"}); + + contextSetup = new Request.ContextSetup("index", new BytesArray("{}"), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + request = new Request(new Script(ScriptType.INLINE, "painless", + "emit(\"test\"); emit(\"baz was not here\"); emit(\"Data\"); emit(\"-10\"); emit(\"20\"); emit(\"9\");", + emptyMap()), "string_field", contextSetup); + response = innerShardOperation(request, scriptService, indexService); + assertArrayEquals((String[])response.getResult(), new String[] {"-10", "20", "9", "Data", "baz was not here", "test"}); + } + public void testContextWhitelists() throws IOException { ScriptService scriptService = getInstanceFromNode(ScriptService.class); // score diff --git a/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/70_execute_painless_scripts.yml b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/70_execute_painless_scripts.yml index 5a994425c5dc2..acf5af632a749 100644 --- a/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/70_execute_painless_scripts.yml +++ b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/70_execute_painless_scripts.yml @@ -11,6 +11,20 @@ setup: type: keyword text: type: text + point: + type: geo_point + p0: + type: geo_point + p1: + type: geo_point + date: + type: date + date0: + type: date + date1: + type: date + ip: + type: ip --- "Execute with defaults": @@ -68,3 +82,214 @@ setup: rank: 4 index: "my-index" - match: { result: 0.8 } + +--- +"Execute with boolean field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value < params.max_rank);" + params: + max_rank: 5.0 + context: "boolean_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ true ] } + + +--- +"Execute with boolean field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value < params.max_rank); emit(false); emit(false); emit(true);" + params: + max_rank: 5.0 + context: "boolean_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ false, false, true, true ] } + +--- +"Execute with date field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['date'].value.toInstant().toEpochMilli())" + context: "date_field" + context_setup: + document: + date: "2015-01-01T12:10:30Z" + index: "my-index" + - match: { result: [ 1420114230000 ] } + +--- +"Execute with date field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['date0'][0].toInstant().toEpochMilli()); emit(doc['date1'][0].toInstant().toEpochMilli());" + context: "date_field" + context_setup: + document: + date0: "2015-01-01T12:10:30Z" + date1: "2010-11-30T13:14:35Z" + index: "my-index" + - match: { result: [ 1291122875000, 1420114230000 ] } + +--- +"Execute with double field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * params.max_rank)" + params: + max_rank: 5.0 + context: "double_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ 20.0 ] } + +--- +"Execute with double field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * params.max_rank); emit(400.0); emit(55.0)" + params: + max_rank: 5.0 + context: "double_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ 20.0, 55.0, 400.0 ] } + +--- +"Execute with geo point field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['point'].value.lat + 1.0, doc['point'].value.lon - 1.0)" + context: "geo_point_field" + context_setup: + document: + point: "30.0,40.0" + index: "my-index" + - match: { result: [ 3176939252927413179 ] } + +--- +"Execute with geo point field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['p0'][0].lat + 1.0, doc['p0'][0].lon - 1.0); emit(doc['p1'][0].lat + 1.0, doc['p1'][0].lon - 1.0)" + context: "geo_point_field" + context_setup: + document: + p0: "30.0,40.0" + p1: "40.0,30.0" + index: "my-index" + - match: { result: [ 3176939252927413179, 4201758367059757556 ] } + +--- +"Execute with ip field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['ip'].value);" + context: "ip_field" + context_setup: + document: + ip: "192.168.1.254" + index: "my-index" + +--- +"Execute with ip field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['ip'].value); emit('127.0.0.1'); emit('255.255.255.255')" + context: "ip_field" + context_setup: + document: + ip: "192.168.1.254" + index: "my-index" + +--- +"Execute with long field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * (long)params.max_rank)" + params: + max_rank: 5.0 + context: "long_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ 20 ] } + +--- +"Execute with long field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * (long)params.max_rank); emit(35); emit(0); emit(-90); emit(20);" + params: + max_rank: 5.0 + context: "long_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ -90, 0, 20, 20, 35 ] } + +--- +"Execute with string field context (single-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['point'].value.lat.toString().substring(0, 5));" + context: "string_field" + context_setup: + document: + point: "30.2,40.2" + index: "my-index" + - match: { result.0: "30.19" } + +--- +"Execute with string field context (multi-value)": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['point'].value.lat.toString().substring(0, 5)); + emit(doc['point'].value.lon.toString().substring(0, 5) + 'test');" + context: "string_field" + context_setup: + document: + point: "30.2,40.2" + index: "my-index" + - match: { result.0: "30.19" } + - match: { result.1: "40.19test" }