From 7fa459946e242abd7c763d6afe8788e711f4b854 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 5 Apr 2021 16:48:18 -0700 Subject: [PATCH 1/7] add rt fields to painless execute action --- .../action/PainlessExecuteAction.java | 95 ++++++++++++++++++- 1 file changed, 92 insertions(+), 3 deletions(-) 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..e62d5756d8092 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 @@ -40,6 +40,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.NamedXContentRegistry; @@ -60,16 +61,26 @@ 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; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -105,7 +116,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", LongFieldScript.CONTEXT, + "date_field", LongFieldScript.CONTEXT, + "double_field", LongFieldScript.CONTEXT, + "geo_point_field", LongFieldScript.CONTEXT, + "ip_field", LongFieldScript.CONTEXT, + "long_field", LongFieldScript.CONTEXT, + "string_field", LongFieldScript.CONTEXT) + ; static ScriptContext fromScriptContextName(String name) { ScriptContext scriptContext = SUPPORTED_CONTEXTS.get(name); @@ -492,7 +511,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 +521,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 +540,76 @@ 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_runtime_field", request.getScript().getParams(), context.lookup()); + BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext); + booleanFieldScript.setDocument(0); + booleanFieldScript.execute(); + return new Response(Map.of("trues", booleanFieldScript.trues(), "falses", booleanFieldScript.falses())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup(), DateFormatter.); + DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext); + dateFieldScript.setDocument(0); + dateFieldScript.execute(); + return new Response(Arrays.copyOf(dateFieldScript.values(), dateFieldScript.count())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup()); + DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext); + doubleFieldScript.setDocument(0); + doubleFieldScript.execute(); + return new Response(Arrays.copyOf(doubleFieldScript.values(), doubleFieldScript.count())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup()); + GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext); + geoPointFieldScript.setDocument(0); + geoPointFieldScript.execute(); + return new Response(Arrays.copyOf(geoPointFieldScript.values(), geoPointFieldScript.count())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup()); + IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext); + ipFieldScript.setDocument(0); + ipFieldScript.execute(); + return new Response(Arrays.copyOf(ipFieldScript.values(), ipFieldScript.count())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup()); + LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext); + longFieldScript.setDocument(0); + longFieldScript.execute(); + return new Response(Arrays.copyOf(longFieldScript.values(), longFieldScript.count())); + }, 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_runtime_field", request.getScript().getParams(), context.lookup()); + StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext); + stringFieldScript.setDocument(0); + stringFieldScript.execute(); + return new Response(stringFieldScript.resultsForDoc(0)); + }, indexService); } else { throw new UnsupportedOperationException("unsupported context [" + scriptContext.name + "]"); } From df768ba6320603a6afb5a3c38b4bcd39f418d3df Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 6 Apr 2021 12:13:58 -0700 Subject: [PATCH 2/7] add some tests --- .../action/PainlessExecuteAction.java | 26 ++++----- .../action/PainlessExecuteApiTests.java | 55 +++++++++++++++++++ .../painless/70_execute_painless_scripts.yml | 1 + 3 files changed, 68 insertions(+), 14 deletions(-) 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 e62d5756d8092..832faaf8c4e8a 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 @@ -40,7 +40,6 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.NamedXContentRegistry; @@ -51,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; @@ -79,8 +79,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -117,13 +115,13 @@ public static class Request extends SingleShardRequest implements ToXCo "painless_test", PainlessTestScript.CONTEXT, "filter", FilterScript.CONTEXT, "score", ScoreScript.CONTEXT, - "boolean_field", LongFieldScript.CONTEXT, - "date_field", LongFieldScript.CONTEXT, - "double_field", LongFieldScript.CONTEXT, - "geo_point_field", LongFieldScript.CONTEXT, - "ip_field", LongFieldScript.CONTEXT, - "long_field", LongFieldScript.CONTEXT, - "string_field", LongFieldScript.CONTEXT) + "boolean_script_field_script_field", BooleanFieldScript.CONTEXT, + "date_script_field", DateFieldScript.CONTEXT, + "double_script_field_script_field", DoubleFieldScript.CONTEXT, + "geo_point_script_field_script_field", GeoPointFieldScript.CONTEXT, + "ip_script_field_script_field", IpFieldScript.CONTEXT, + "long_script_field_script_field", LongFieldScript.CONTEXT, + "string_script_field_script_field", StringFieldScript.CONTEXT) ; static ScriptContext fromScriptContextName(String name) { @@ -550,16 +548,16 @@ static Response innerShardOperation(Request request, ScriptService scriptService booleanFieldScript.execute(); return new Response(Map.of("trues", booleanFieldScript.trues(), "falses", booleanFieldScript.falses())); }, indexService); - /*} else if (scriptContext == DateFieldScript.CONTEXT) { + } 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_runtime_field", request.getScript().getParams(), context.lookup(), DateFormatter.); + DateFieldScript.LeafFactory leafFactory = factory.newFactory("date_runtime_field", + request.getScript().getParams(), context.lookup(), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext); dateFieldScript.setDocument(0); dateFieldScript.execute(); return new Response(Arrays.copyOf(dateFieldScript.values(), dateFieldScript.count())); - }, indexService);*/ + }, indexService); } else if (scriptContext == DoubleFieldScript.CONTEXT) { return prepareRamIndex(request, (context, leafReaderContext) -> { DoubleFieldScript.Factory factory = scriptService.compile(request.script, DoubleFieldScript.CONTEXT); 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..b6416a84bbbf9 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 @@ -11,6 +11,7 @@ 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; @@ -23,11 +24,15 @@ import org.elasticsearch.test.ESSingleNodeTestCase; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; 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 +105,56 @@ 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_script_field_script_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + Map result = new HashMap<>(); + result.put("trues", 1); + result.put("falses", 0); + assertEquals(response.getResult(), result); + } + + 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.getMillis())", emptyMap()), "date_script_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + long[] result = new long[1]; + result[0] = 1420114230000L; + assertArrayEquals((long[])response.getResult(), result); + } + + 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_script_field_script_field", + contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + double[] result = new double[2]; + result[0] = 4.0; + result[1] = Math.log(4.0); + assertArrayEquals((double[])response.getResult(), result, 0.00001); + } + 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..1e763712ed993 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 @@ -68,3 +68,4 @@ setup: rank: 4 index: "my-index" - match: { result: 0.8 } + From 105c7cd94fa7d1b50399f55ba166e26f182d3487 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 6 Apr 2021 12:39:43 -0700 Subject: [PATCH 3/7] finish single node tests --- .../action/PainlessExecuteApiTests.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) 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 b6416a84bbbf9..b804ef891abc3 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,6 +7,7 @@ */ 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; @@ -155,6 +156,73 @@ public void testDoubleFieldExecutionContext() throws IOException { assertArrayEquals((double[])response.getResult(), result, 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_script_field_script_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + long[] result = new long[1]; + result[0] = 3176939252927413179L; + assertArrayEquals((long[])response.getResult(), result); + } + + 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_script_field_script_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + BytesRef[] result = new BytesRef[1]; + result[0] = 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}); + assertArrayEquals((BytesRef[])response.getResult(), result); + } + + 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_script_field_script_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + long[] result = new long[2]; + result[0] = 30; + result[1] = 40; + assertArrayEquals((long[])response.getResult(), result); + } + + 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_script_field_script_field", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + List result = new ArrayList<>(); + result.add("30.19"); + result.add("40.19"); + assertEquals(response.getResult(), result); + } + public void testContextWhitelists() throws IOException { ScriptService scriptService = getInstanceFromNode(ScriptService.class); // score From ab58a91bfd0f1746c1e6d00b093ce5683c500b06 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 6 Apr 2021 14:05:50 -0700 Subject: [PATCH 4/7] add yaml tests --- .../action/PainlessExecuteApiTests.java | 3 +- .../painless/70_execute_painless_scripts.yml | 110 ++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) 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 b804ef891abc3..a37010f631025 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 @@ -26,7 +26,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -131,7 +130,7 @@ public void testDateFieldExecutionContext() throws IOException { 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.getMillis())", emptyMap()), "date_script_field", + "emit(doc['test_date'].value.toInstant().toEpochMilli())", emptyMap()), "date_script_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); long[] result = new long[1]; 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 1e763712ed993..aa0d55a6fe9e6 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,12 @@ setup: type: keyword text: type: text + point: + type: geo_point + date: + type: date + ip: + type: ip --- "Execute with defaults": @@ -69,3 +75,107 @@ setup: index: "my-index" - match: { result: 0.8 } +--- +"Execute with boolean field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value < params.max_rank)" + params: + max_rank: 5.0 + context: "boolean_script_field_script_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: { trues: 1, falses: 0 } } + +--- +"Execute with date field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['date'].value.toInstant().toEpochMilli())" + context: "double_script_field_script_field" + context_setup: + document: + date: "2015-01-01T12:10:30Z" + index: "my-index" + - match: { result: [ 1.42011423E12 ] } + +--- +"Execute with double field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * params.max_rank)" + params: + max_rank: 5.0 + context: "double_script_field_script_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ 20.0 ] } + +--- +"Execute with geo point field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['point'].value.lat + 1.0, doc['point'].value.lon - 1.0)" + context: "geo_point_script_field_script_field" + context_setup: + document: + point: "30.0,40.0" + index: "my-index" + - match: { result: [ 3176939252927413179 ] } + +--- +"Execute with ip field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['ip'].value);" + context: "ip_script_field_script_field" + context_setup: + document: + ip: "192.168.1.254" + index: "my-index" + +--- +"Execute with long field context": + - do: + scripts_painless_execute: + body: + script: + source: "emit(doc['rank'].value * (long)params.max_rank)" + params: + max_rank: 5.0 + context: "long_script_field_script_field" + context_setup: + document: + rank: 4 + index: "my-index" + - match: { result: [ 20 ] } + +--- +"Execute with string field context": + - 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));" + context: "string_script_field_script_field" + context_setup: + document: + point: "30.2,40.2" + index: "my-index" + - match: { result.0: "30.19" } + - match: { result.1: "40.19" } From 96344073df5cd5411438288288fc740f757ec851 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 13 Apr 2021 11:15:49 -0700 Subject: [PATCH 5/7] update based on pr feedback --- .../action/PainlessExecuteAction.java | 64 +++++----- .../action/PainlessExecuteApiTests.java | 111 ++++++++++++------ .../painless/70_execute_painless_scripts.yml | 95 +-------------- 3 files changed, 108 insertions(+), 162 deletions(-) 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 832faaf8c4e8a..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 @@ -78,7 +78,6 @@ import org.elasticsearch.transport.TransportService; import java.io.IOException; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; @@ -115,13 +114,13 @@ public static class Request extends SingleShardRequest implements ToXCo "painless_test", PainlessTestScript.CONTEXT, "filter", FilterScript.CONTEXT, "score", ScoreScript.CONTEXT, - "boolean_script_field_script_field", BooleanFieldScript.CONTEXT, - "date_script_field", DateFieldScript.CONTEXT, - "double_script_field_script_field", DoubleFieldScript.CONTEXT, - "geo_point_script_field_script_field", GeoPointFieldScript.CONTEXT, - "ip_script_field_script_field", IpFieldScript.CONTEXT, - "long_script_field_script_field", LongFieldScript.CONTEXT, - "string_script_field_script_field", StringFieldScript.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) { @@ -542,71 +541,64 @@ static Response innerShardOperation(Request request, ScriptService scriptService return prepareRamIndex(request, (context, leafReaderContext) -> { BooleanFieldScript.Factory factory = scriptService.compile(request.script, BooleanFieldScript.CONTEXT); BooleanFieldScript.LeafFactory leafFactory = - factory.newFactory("boolean_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("boolean_field", request.getScript().getParams(), context.lookup()); BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext); - booleanFieldScript.setDocument(0); - booleanFieldScript.execute(); - return new Response(Map.of("trues", booleanFieldScript.trues(), "falses", booleanFieldScript.falses())); + 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_runtime_field", + DateFieldScript.LeafFactory leafFactory = factory.newFactory("date_field", request.getScript().getParams(), context.lookup(), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext); - dateFieldScript.setDocument(0); - dateFieldScript.execute(); - return new Response(Arrays.copyOf(dateFieldScript.values(), dateFieldScript.count())); + 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_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("double_field", request.getScript().getParams(), context.lookup()); DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext); - doubleFieldScript.setDocument(0); - doubleFieldScript.execute(); - return new Response(Arrays.copyOf(doubleFieldScript.values(), doubleFieldScript.count())); + 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_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("geo_point_field", request.getScript().getParams(), context.lookup()); GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext); - geoPointFieldScript.setDocument(0); - geoPointFieldScript.execute(); - return new Response(Arrays.copyOf(geoPointFieldScript.values(), geoPointFieldScript.count())); + 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_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("ip_field", request.getScript().getParams(), context.lookup()); IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext); - ipFieldScript.setDocument(0); - ipFieldScript.execute(); - return new Response(Arrays.copyOf(ipFieldScript.values(), ipFieldScript.count())); + 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_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("long_field", request.getScript().getParams(), context.lookup()); LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext); - longFieldScript.setDocument(0); - longFieldScript.execute(); - return new Response(Arrays.copyOf(longFieldScript.values(), longFieldScript.count())); + 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_runtime_field", request.getScript().getParams(), context.lookup()); + factory.newFactory("string_field", request.getScript().getParams(), context.lookup()); StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext); - stringFieldScript.setDocument(0); - stringFieldScript.execute(); - return new Response(stringFieldScript.resultsForDoc(0)); + 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 a37010f631025..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 @@ -25,11 +25,9 @@ import org.elasticsearch.test.ESSingleNodeTestCase; import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import static java.util.Collections.emptyMap; @@ -113,13 +111,18 @@ public void testBooleanFieldExecutionContext() throws IOException { 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_script_field_script_field", + "emit(doc['rank'].value < params.max_rank)", singletonMap("max_rank", 5.0)), "boolean_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - Map result = new HashMap<>(); - result.put("trues", 1); - result.put("falses", 0); - assertEquals(response.getResult(), result); + 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 { @@ -130,12 +133,20 @@ public void testDateFieldExecutionContext() throws IOException { 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_script_field", + "emit(doc['test_date'].value.toInstant().toEpochMilli())", emptyMap()), "date_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - long[] result = new long[1]; - result[0] = 1420114230000L; - assertArrayEquals((long[])response.getResult(), result); + 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 { @@ -146,13 +157,18 @@ public void testDoubleFieldExecutionContext() throws IOException { 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_script_field_script_field", + "emit(doc['rank'].value); emit(Math.log(doc['rank'].value))", emptyMap()), "double_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - double[] result = new double[2]; - result[0] = 4.0; - result[1] = Math.log(4.0); - assertArrayEquals((double[])response.getResult(), result, 0.00001); + 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 { @@ -164,11 +180,17 @@ public void testGeoPointFieldExecutionContext() throws IOException { 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_script_field_script_field", contextSetup); + "geo_point_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - long[] result = new long[1]; - result[0] = 3176939252927413179L; - assertArrayEquals((long[])response.getResult(), result); + 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 { @@ -180,11 +202,22 @@ public void testIpFieldExecutionContext() throws IOException { contextSetup.setXContentType(XContentType.JSON); Request request = new Request(new Script(ScriptType.INLINE, "painless", "emit(doc['test_ip'].value);", emptyMap()), - "ip_script_field_script_field", contextSetup); + "ip_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - BytesRef[] result = new BytesRef[1]; - result[0] = 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}); - assertArrayEquals((BytesRef[])response.getResult(), result); + 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 { @@ -196,12 +229,17 @@ public void testLongFieldExecutionContext() throws IOException { 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_script_field_script_field", contextSetup); + "long_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - long[] result = new long[2]; - result[0] = 30; - result[1] = 40; - assertArrayEquals((long[])response.getResult(), result); + 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 { @@ -214,12 +252,17 @@ public void testStringFieldExecutionContext() throws IOException { 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_script_field_script_field", contextSetup); + "string_field", contextSetup); Response response = innerShardOperation(request, scriptService, indexService); - List result = new ArrayList<>(); - result.add("30.19"); - result.add("40.19"); - assertEquals(response.getResult(), result); + 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 { 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 aa0d55a6fe9e6..0b7d7a3b7649f 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 @@ -81,101 +81,12 @@ setup: scripts_painless_execute: body: script: - source: "emit(doc['rank'].value < params.max_rank)" + source: "emit(doc['rank'].value < params.max_rank); emit(false); emit(false); emit(true);" params: max_rank: 5.0 - context: "boolean_script_field_script_field" + context: "boolean_field" context_setup: document: rank: 4 index: "my-index" - - match: { result: { trues: 1, falses: 0 } } - ---- -"Execute with date field context": - - do: - scripts_painless_execute: - body: - script: - source: "emit(doc['date'].value.toInstant().toEpochMilli())" - context: "double_script_field_script_field" - context_setup: - document: - date: "2015-01-01T12:10:30Z" - index: "my-index" - - match: { result: [ 1.42011423E12 ] } - ---- -"Execute with double field context": - - do: - scripts_painless_execute: - body: - script: - source: "emit(doc['rank'].value * params.max_rank)" - params: - max_rank: 5.0 - context: "double_script_field_script_field" - context_setup: - document: - rank: 4 - index: "my-index" - - match: { result: [ 20.0 ] } - ---- -"Execute with geo point field context": - - do: - scripts_painless_execute: - body: - script: - source: "emit(doc['point'].value.lat + 1.0, doc['point'].value.lon - 1.0)" - context: "geo_point_script_field_script_field" - context_setup: - document: - point: "30.0,40.0" - index: "my-index" - - match: { result: [ 3176939252927413179 ] } - ---- -"Execute with ip field context": - - do: - scripts_painless_execute: - body: - script: - source: "emit(doc['ip'].value);" - context: "ip_script_field_script_field" - context_setup: - document: - ip: "192.168.1.254" - index: "my-index" - ---- -"Execute with long field context": - - do: - scripts_painless_execute: - body: - script: - source: "emit(doc['rank'].value * (long)params.max_rank)" - params: - max_rank: 5.0 - context: "long_script_field_script_field" - context_setup: - document: - rank: 4 - index: "my-index" - - match: { result: [ 20 ] } - ---- -"Execute with string field context": - - 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));" - context: "string_script_field_script_field" - context_setup: - document: - point: "30.2,40.2" - index: "my-index" - - match: { result.0: "30.19" } - - match: { result.1: "40.19" } + - match: { result: [ false, false, true, true ] } From 6b40ed1f32b03747991df02da94eb4ab81cd56cd Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 13 Apr 2021 12:50:54 -0700 Subject: [PATCH 6/7] some yaml tests updated --- .../common/xcontent/XContentBuilder.java | 1 + .../painless/70_execute_painless_scripts.yml | 84 ++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java index f1d823049a4d5..896e77a0ba49e 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java @@ -95,6 +95,7 @@ public static XContentBuilder builder(XContentType xContentType, Set inc static { Map, Writer> writers = new HashMap<>(); writers.put(Boolean.class, (b, v) -> b.value((Boolean) v)); + writers.put(boolean[].class, (b, v) -> b.values((boolean[]) v)); writers.put(Byte.class, (b, v) -> b.value((Byte) v)); writers.put(byte[].class, (b, v) -> b.value((byte[]) v)); writers.put(Date.class, XContentBuilder::timeValue); 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 0b7d7a3b7649f..0eab2574491f6 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 @@ -15,6 +15,10 @@ setup: type: geo_point date: type: date + date0: + type: date + date1: + type: date ip: type: ip @@ -76,7 +80,24 @@ setup: - match: { result: 0.8 } --- -"Execute with boolean field context": +"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: @@ -90,3 +111,64 @@ setup: 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 ] } From 0c78bea395ff7568ebb77bd2d9c5f54ff03c85f3 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 13 Apr 2021 13:38:45 -0700 Subject: [PATCH 7/7] finish updating yaml tests --- .../painless/70_execute_painless_scripts.yml | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) 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 0eab2574491f6..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 @@ -13,6 +13,10 @@ setup: type: text point: type: geo_point + p0: + type: geo_point + p1: + type: geo_point date: type: date date0: @@ -172,3 +176,120 @@ setup: 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" }