Make Painless the default scripting language.

Closes #20017
This commit is contained in:
Jack Conradson 2016-08-22 17:38:02 -07:00
parent 514585290c
commit 131e370a16
10 changed files with 77 additions and 22 deletions

View File

@ -32,7 +32,7 @@ import java.util.function.Function;
public class ScriptSettings {
public static final String DEFAULT_LANG = "groovy";
public static final String DEFAULT_LANG = "painless";
private static final Map<ScriptService.ScriptType, Setting<Boolean>> SCRIPT_TYPE_SETTING_MAP;
@ -59,7 +59,7 @@ public class ScriptSettings {
this.scriptLanguageSettings = Collections.unmodifiableList(scriptLanguageSettings);
this.defaultScriptLanguageSetting = new Setting<>("script.default_lang", DEFAULT_LANG, setting -> {
if (!"groovy".equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) {
if (!DEFAULT_LANG.equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) {
throw new IllegalArgumentException("unregistered default language [" + setting + "]");
}
return setting;

View File

@ -32,12 +32,12 @@ import static org.hamcrest.Matchers.equalTo;
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() {

View File

@ -165,7 +165,7 @@ POST /sales/_search
"count": "categories._bucket_count" <1>
},
"script": {
"inline": "count != 0"
"inline": "params.count != 0"
}
}
}

View File

@ -77,7 +77,7 @@ POST /sales/_search
"tShirtSales": "t-shirts>sales",
"totalSales": "total_sales"
},
"script": "tShirtSales / totalSales * 100"
"script": "params.tShirtSales / params.totalSales * 100"
}
}
}

View File

@ -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"
}
}
}

View File

@ -1,6 +1,53 @@
[[breaking_50_scripting]]
=== Script related changes
==== Switched Default Language from Groovy to Painless
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 <<modules-scripting-painless,Painless Scripting Language>>
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 use 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

View File

@ -70,12 +70,12 @@ public class GroovyIndexedScriptTests extends ESIntegTestCase {
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 class GroovyIndexedScriptTests extends ESIntegTestCase {
.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 class GroovyIndexedScriptTests extends ESIntegTestCase {
.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);
@ -157,7 +159,7 @@ public class GroovyIndexedScriptTests extends ESIntegTestCase {
.prepareSearch("test")
.setSource(
new SearchSourceBuilder().aggregation(AggregationBuilders.terms("test").script(
new Script("script1", ScriptType.STORED, null, null)))).get();
new Script("script1", ScriptType.STORED, GroovyScriptEngineService.NAME, null)))).get();
assertHitCount(searchResponse, 1);
assertThat(searchResponse.getAggregations().get("test"), notNullValue());
}

View File

@ -68,7 +68,7 @@ public class GroovyScriptTests extends ESIntegTestCase {
}
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)))
@ -99,7 +99,8 @@ public class GroovyScriptTests extends ESIntegTestCase {
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",
@ -118,8 +119,9 @@ public class GroovyScriptTests extends ESIntegTestCase {
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");
@ -133,7 +135,7 @@ public class GroovyScriptTests extends ESIntegTestCase {
// _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");
@ -144,9 +146,9 @@ public class GroovyScriptTests extends ESIntegTestCase {
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");
}

View File

@ -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

View File

@ -34,6 +34,7 @@
script:
inline: "ctx._source.foo = bar"
params: { bar: 'xxx' }
lang: "groovy"
- do:
update: