From 72aa71535290f5bf6d0d82a348f8a04b652645c6 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 15 Aug 2016 09:19:25 -0700 Subject: [PATCH 1/5] Fixed tests to ensure Painless default in ES. --- .../main/java/org/elasticsearch/script/ScriptSettings.java | 4 ++-- .../java/org/elasticsearch/script/ScriptSettingsTests.java | 4 ++-- .../elasticsearch/script/groovy/GroovyIndexedScriptTests.java | 4 ++-- .../org/elasticsearch/script/groovy/GroovyScriptTests.java | 3 +-- .../rest-api-spec/test/lang_groovy/25_script_upsert.yaml | 3 +++ .../resources/rest-api-spec/test/lang_groovy/90_missing.yaml | 1 + 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/script/ScriptSettings.java b/core/src/main/java/org/elasticsearch/script/ScriptSettings.java index e315f8d816cb7..0a98425828eb3 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptSettings.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptSettings.java @@ -32,7 +32,7 @@ public class ScriptSettings { - public static final String DEFAULT_LANG = "groovy"; + public static final String DEFAULT_LANG = "painless"; private static final Map> SCRIPT_TYPE_SETTING_MAP; @@ -59,7 +59,7 @@ public ScriptSettings(ScriptEngineRegistry scriptEngineRegistry, ScriptContextRe this.scriptLanguageSettings = Collections.unmodifiableList(scriptLanguageSettings); this.defaultScriptLanguageSetting = new Setting<>("script.default_lang", DEFAULT_LANG, setting -> { - if (!"groovy".equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) { + if (!"painless".equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) { throw new IllegalArgumentException("unregistered default language [" + setting + "]"); } return setting; diff --git a/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java b/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java index 053ccec652cc8..8c1654fb902a9 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java @@ -32,12 +32,12 @@ public class ScriptSettingsTests extends ESTestCase { - public void testDefaultLanguageIsGroovy() { + public void testDefaultLanguageIsPainless() { ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new CustomScriptEngineService())); ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList()); ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry); - assertThat(scriptSettings.getDefaultScriptLanguageSetting().get(Settings.EMPTY), equalTo("groovy")); + assertThat(scriptSettings.getDefaultScriptLanguageSetting().get(Settings.EMPTY), equalTo("painless")); } public void testCustomDefaultLanguage() { diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java index be307c690f957..7d21eeafe21a1 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java @@ -136,7 +136,7 @@ public void testDisabledUpdateIndexedScriptsOnly() { client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get(); try { client().prepareUpdate("test", "scriptTest", "1") - .setScript(new Script("script1", ScriptService.ScriptType.STORED, GroovyScriptEngineService.NAME, null)).get(); + .setScript(new Script("script1", ScriptService.ScriptType.STORED, "groovy", null)).get(); fail("update script should have been rejected"); } catch (Exception e) { assertThat(e.getMessage(), containsString("failed to execute script")); @@ -157,7 +157,7 @@ public void testDisabledAggsDynamicScripts() { .prepareSearch("test") .setSource( new SearchSourceBuilder().aggregation(AggregationBuilders.terms("test").script( - new Script("script1", ScriptType.STORED, null, null)))).get(); + new Script("script1", ScriptType.STORED, "groovy", null)))).get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getAggregations().get("test"), notNullValue()); } diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java index f2eee2bb40833..d67b3a071e72f 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java @@ -85,8 +85,7 @@ public void testGroovyExceptionSerialization() throws Exception { try { client().prepareSearch("test") .setQuery( - constantScoreQuery(scriptQuery(new Script("1 == not_found", ScriptType.INLINE, GroovyScriptEngineService.NAME, - null)))).get(); + constantScoreQuery(scriptQuery(new Script("1 == not_found", ScriptType.INLINE, "groovy", null)))).get(); fail("should have thrown an exception"); } catch (SearchPhaseExecutionException e) { assertThat(e.toString()+ "should not contained NotSerializableTransportException", diff --git a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/25_script_upsert.yaml b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/25_script_upsert.yaml index 3ab70d084fae1..6ba4d39e71b2d 100644 --- a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/25_script_upsert.yaml +++ b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/25_script_upsert.yaml @@ -13,6 +13,7 @@ script: inline: "ctx._source.foo = bar" params: { bar: 'xxx' } + lang: "groovy" upsert: { foo: baz } - do: @@ -33,6 +34,7 @@ script: inline: "ctx._source.foo = bar" params: { bar: 'xxx' } + lang: "groovy" upsert: { foo: baz } - do: @@ -52,6 +54,7 @@ script: inline: "ctx._source.foo = bar" params: { bar: 'xxx' } + lang: "groovy" upsert: { foo: baz } scripted_upsert: true diff --git a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/90_missing.yaml b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/90_missing.yaml index c49565a6304a0..999d9f610ffb0 100644 --- a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/90_missing.yaml +++ b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/90_missing.yaml @@ -34,6 +34,7 @@ script: inline: "ctx._source.foo = bar" params: { bar: 'xxx' } + lang: "groovy" - do: update: From 1bef0b360ee8da0c0daaad4a88e50c6708d334b4 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 16 Aug 2016 18:27:51 -0700 Subject: [PATCH 2/5] Fixed some constants. --- .../org/elasticsearch/script/ScriptSettings.java | 2 +- .../script/groovy/GroovyIndexedScriptTests.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/script/ScriptSettings.java b/core/src/main/java/org/elasticsearch/script/ScriptSettings.java index 0a98425828eb3..3301e2e08aaba 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptSettings.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptSettings.java @@ -59,7 +59,7 @@ public ScriptSettings(ScriptEngineRegistry scriptEngineRegistry, ScriptContextRe this.scriptLanguageSettings = Collections.unmodifiableList(scriptLanguageSettings); this.defaultScriptLanguageSetting = new Setting<>("script.default_lang", DEFAULT_LANG, setting -> { - if (!"painless".equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) { + if (!DEFAULT_LANG.equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) { throw new IllegalArgumentException("unregistered default language [" + setting + "]"); } return setting; diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java index 7d21eeafe21a1..b0d5fd3366baa 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyIndexedScriptTests.java @@ -70,12 +70,12 @@ protected Settings nodeSettings(int nodeOrdinal) { public void testFieldIndexedScript() throws ExecutionException, InterruptedException { client().admin().cluster().preparePutStoredScript() .setId("script1") - .setScriptLang("groovy") + .setScriptLang(GroovyScriptEngineService.NAME) .setSource(new BytesArray("{ \"script\" : \"2\"}")) .get(); client().admin().cluster().preparePutStoredScript() .setId("script2") - .setScriptLang("groovy") + .setScriptLang(GroovyScriptEngineService.NAME) .setSource(new BytesArray("{ \"script\" : \"factor * 2\"}")) .get(); @@ -93,8 +93,9 @@ public void testFieldIndexedScript() throws ExecutionException, InterruptedExce .prepareSearch() .setSource( new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()).size(1) - .scriptField("test1", new Script("script1", ScriptType.STORED, "groovy", null)) - .scriptField("test2", new Script("script2", ScriptType.STORED, "groovy", script2Params))) + .scriptField("test1", new Script("script1", ScriptType.STORED, GroovyScriptEngineService.NAME, null)) + .scriptField("test2", + new Script("script2", ScriptType.STORED, GroovyScriptEngineService.NAME, script2Params))) .setIndices("test").setTypes("scriptTest").get(); assertHitCount(searchResponse, 5); assertTrue(searchResponse.getHits().hits().length == 1); @@ -120,7 +121,8 @@ public void testUpdateScripts() { .prepareSearch() .setSource( new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()).scriptField("test_field", - new Script("script1", ScriptType.STORED, "groovy", null))).setIndices("test_index") + new Script("script1", ScriptType.STORED, GroovyScriptEngineService.NAME, null))) + .setIndices("test_index") .setTypes("test_type").get(); assertHitCount(searchResponse, 1); SearchHit sh = searchResponse.getHits().getAt(0); @@ -136,7 +138,7 @@ public void testDisabledUpdateIndexedScriptsOnly() { client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get(); try { client().prepareUpdate("test", "scriptTest", "1") - .setScript(new Script("script1", ScriptService.ScriptType.STORED, "groovy", null)).get(); + .setScript(new Script("script1", ScriptService.ScriptType.STORED, GroovyScriptEngineService.NAME, null)).get(); fail("update script should have been rejected"); } catch (Exception e) { assertThat(e.getMessage(), containsString("failed to execute script")); @@ -157,7 +159,7 @@ public void testDisabledAggsDynamicScripts() { .prepareSearch("test") .setSource( new SearchSourceBuilder().aggregation(AggregationBuilders.terms("test").script( - new Script("script1", ScriptType.STORED, "groovy", null)))).get(); + new Script("script1", ScriptType.STORED, GroovyScriptEngineService.NAME, null)))).get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getAggregations().get("test"), notNullValue()); } From be326553054daaf2997d012a434e71553c6bf0b2 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 17 Aug 2016 08:48:14 -0700 Subject: [PATCH 3/5] Fix more constants. --- .../script/groovy/GroovyScriptTests.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java index d67b3a071e72f..88d9b7be1de7f 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovyScriptTests.java @@ -68,7 +68,7 @@ public void testGroovyBigDecimalTransformation() { } public void assertScript(String scriptString) { - Script script = new Script(scriptString, ScriptType.INLINE, "groovy", null); + Script script = new Script(scriptString, ScriptType.INLINE, GroovyScriptEngineService.NAME, null); SearchResponse resp = client().prepareSearch("test") .setSource(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()).sort(SortBuilders. scriptSort(script, ScriptSortType.NUMBER))) @@ -85,7 +85,8 @@ public void testGroovyExceptionSerialization() throws Exception { try { client().prepareSearch("test") .setQuery( - constantScoreQuery(scriptQuery(new Script("1 == not_found", ScriptType.INLINE, "groovy", null)))).get(); + constantScoreQuery(scriptQuery(new Script("1 == not_found", ScriptType.INLINE, GroovyScriptEngineService.NAME, + null)))).get(); fail("should have thrown an exception"); } catch (SearchPhaseExecutionException e) { assertThat(e.toString()+ "should not contained NotSerializableTransportException", @@ -98,7 +99,8 @@ public void testGroovyExceptionSerialization() throws Exception { try { client().prepareSearch("test") - .setQuery(constantScoreQuery(scriptQuery(new Script("null.foo", ScriptType.INLINE, "groovy", null)))).get(); + .setQuery(constantScoreQuery(scriptQuery( + new Script("null.foo", ScriptType.INLINE, GroovyScriptEngineService.NAME, null)))).get(); fail("should have thrown an exception"); } catch (SearchPhaseExecutionException e) { assertThat(e.toString() + "should not contained NotSerializableTransportException", @@ -117,8 +119,9 @@ public void testGroovyScriptAccess() { refresh(); // doc[] access - SearchResponse resp = client().prepareSearch("test").setQuery(functionScoreQuery(scriptFunction(new Script("doc['bar'].value", ScriptType.INLINE, "groovy", null))) - .boostMode(CombineFunction.REPLACE)).get(); + SearchResponse resp = client().prepareSearch("test").setQuery(functionScoreQuery(scriptFunction( + new Script("doc['bar'].value", ScriptType.INLINE, GroovyScriptEngineService.NAME, null))) + .boostMode(CombineFunction.REPLACE)).get(); assertNoFailures(resp); assertOrderedSearchHits(resp, "3", "2", "1"); @@ -132,7 +135,7 @@ public void testScoreAccess() { // _score can be accessed SearchResponse resp = client().prepareSearch("test").setQuery(functionScoreQuery(matchQuery("foo", "dog"), - scriptFunction(new Script("_score", ScriptType.INLINE, "groovy", null))) + scriptFunction(new Script("_score", ScriptType.INLINE, GroovyScriptEngineService.NAME, null))) .boostMode(CombineFunction.REPLACE)).get(); assertNoFailures(resp); assertSearchHits(resp, "3", "1"); @@ -143,9 +146,9 @@ public void testScoreAccess() { resp = client() .prepareSearch("test") .setQuery( - functionScoreQuery(matchQuery("foo", "dog"), - scriptFunction(new Script("_score > 0.0 ? _score : 0", ScriptType.INLINE, "groovy", null))).boostMode( - CombineFunction.REPLACE)).get(); + functionScoreQuery(matchQuery("foo", "dog"), scriptFunction( + new Script("_score > 0.0 ? _score : 0", ScriptType.INLINE, GroovyScriptEngineService.NAME, null))) + .boostMode(CombineFunction.REPLACE)).get(); assertNoFailures(resp); assertSearchHits(resp, "3", "1"); } From 3baf05a2c9067768ed1d637025d1f3f33db8ba8d Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 17 Aug 2016 09:38:58 -0700 Subject: [PATCH 4/5] Updated the migration docs for Painless as the default language. --- .../migration/migrate_5_0/scripting.asciidoc | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/reference/migration/migrate_5_0/scripting.asciidoc b/docs/reference/migration/migrate_5_0/scripting.asciidoc index 52a26c89d1b7b..d8ab3f06e3344 100644 --- a/docs/reference/migration/migrate_5_0/scripting.asciidoc +++ b/docs/reference/migration/migrate_5_0/scripting.asciidoc @@ -1,6 +1,54 @@ [[breaking_50_scripting]] === Script related changes +==== Switched Default Language to Painless + +The default scripting language for Elasticsearch is now Painless. Painless is a language similar to Groovy, except +faster and more secure. Many Groovy scripts will be identitical to Painless scripts to help make the transition +between languages as simple as possible. + +Documentation for Painless can be found at +https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-painless.html + +It is also possible to set the default language back to Groovy using the following setting: `script.default_lang: groovy` + +One common difference to note between Groovy and Painless is the user of parameters -- all parameters in Painless +must be prefixed with `params` now. The following example shows the difference: + +Groovy: + +[source,js] +----------------------------------- +{ + "script_score": { + "script": { + "lang": "groovy", + "inline": "Math.log(_score * 2) + my_modifier", + "params": { + "my_modifier": 8 + } + } + } +} +----------------------------------- + +Painless (`my_modifer` is prefixed with `params`): + +[source,js] +----------------------------------- +{ + "script_score": { + "script": { + "lang": "painless", + "inline": "Math.log(_score * 2) + params.my_modifier", + "params": { + "my_modifier": 8 + } + } + } +} +----------------------------------- + ==== Removed 1.x script and template syntax The deprecated 1.x syntax of defining inline scripts / templates and referring to file or index base scripts / templates From 7612f5fd57a0be3090c2373265b7876e67a5b013 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 22 Aug 2016 15:02:26 -0700 Subject: [PATCH 5/5] More test fixes and updated migration docs. --- docs/reference/aggregations/pipeline.asciidoc | 2 +- .../pipeline/bucket-script-aggregation.asciidoc | 2 +- .../pipeline/bucket-selector-aggregation.asciidoc | 4 ++-- .../migration/migrate_5_0/scripting.asciidoc | 15 +++++++-------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/reference/aggregations/pipeline.asciidoc b/docs/reference/aggregations/pipeline.asciidoc index da78e18855933..499438256e62f 100644 --- a/docs/reference/aggregations/pipeline.asciidoc +++ b/docs/reference/aggregations/pipeline.asciidoc @@ -165,7 +165,7 @@ POST /sales/_search "count": "categories._bucket_count" <1> }, "script": { - "inline": "count != 0" + "inline": "params.count != 0" } } } diff --git a/docs/reference/aggregations/pipeline/bucket-script-aggregation.asciidoc b/docs/reference/aggregations/pipeline/bucket-script-aggregation.asciidoc index 1bfd080090a63..6a010650e5c03 100644 --- a/docs/reference/aggregations/pipeline/bucket-script-aggregation.asciidoc +++ b/docs/reference/aggregations/pipeline/bucket-script-aggregation.asciidoc @@ -77,7 +77,7 @@ POST /sales/_search "tShirtSales": "t-shirts>sales", "totalSales": "total_sales" }, - "script": "tShirtSales / totalSales * 100" + "script": "params.tShirtSales / params.totalSales * 100" } } } diff --git a/docs/reference/aggregations/pipeline/bucket-selector-aggregation.asciidoc b/docs/reference/aggregations/pipeline/bucket-selector-aggregation.asciidoc index 86a56a77aa26d..685c40f48308d 100644 --- a/docs/reference/aggregations/pipeline/bucket-selector-aggregation.asciidoc +++ b/docs/reference/aggregations/pipeline/bucket-selector-aggregation.asciidoc @@ -23,7 +23,7 @@ A `bucket_selector` aggregation looks like this in isolation: "my_var1": "the_sum", <1> "my_var2": "the_value_count" }, - "script": "my_var1 > my_var2" + "script": "params.my_var1 > params.my_var2" } } -------------------------------------------------- @@ -66,7 +66,7 @@ POST /sales/_search "buckets_path": { "totalSales": "total_sales" }, - "script": "totalSales > 200" + "script": "params.totalSales > 200" } } } diff --git a/docs/reference/migration/migrate_5_0/scripting.asciidoc b/docs/reference/migration/migrate_5_0/scripting.asciidoc index d8ab3f06e3344..4d42ae98b460b 100644 --- a/docs/reference/migration/migrate_5_0/scripting.asciidoc +++ b/docs/reference/migration/migrate_5_0/scripting.asciidoc @@ -1,19 +1,18 @@ [[breaking_50_scripting]] === Script related changes -==== Switched Default Language to Painless +==== Switched Default Language from Groovy to Painless -The default scripting language for Elasticsearch is now Painless. Painless is a language similar to Groovy, except -faster and more secure. Many Groovy scripts will be identitical to Painless scripts to help make the transition -between languages as simple as possible. +The default scripting language for Elasticsearch is now Painless. Painless is a custom-built language with syntax +similar to Groovy designed to be fast as well as secure. Many Groovy scripts will be identitical to Painless scripts +to help make the transition between languages as simple as possible. -Documentation for Painless can be found at -https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-painless.html +Documentation for Painless can be found at <> It is also possible to set the default language back to Groovy using the following setting: `script.default_lang: groovy` -One common difference to note between Groovy and Painless is the user of parameters -- all parameters in Painless -must be prefixed with `params` now. The following example shows the difference: +One common difference to note between Groovy and Painless is the use of parameters -- all parameters in Painless +must be prefixed with `params.` now. The following example shows the difference: Groovy: