Skip to content

Commit

Permalink
* Removed script.default_lang setting and made painless the hardc…
Browse files Browse the repository at this point in the history
…oded default script language.

** The default script language is now maintained in `Script` class.
* Added `script.legacy.default_lang` setting that controls the default language for scripts that are stored inside documents (for example percolator queries).  This defaults to groovy.
** Added `QueryParseContext#getDefaultScriptLanguage()` that manages the default scripting language. Returns always `painless`, unless loading query/search request in legacy mode then the returns what is configured in `script.legacy.default_lang` setting.
** In the aggregation parsing code added `ParserContext` that also holds the default scripting language like `QueryParseContext`. Most parser don't have access to `QueryParseContext`. This is for scripts in aggregations.
* The `lang` script field is always serialized (toXContent).

Closes elastic#20122
  • Loading branch information
martijnvg committed Sep 6, 2016
1 parent 0d7dfcd commit 245882c
Show file tree
Hide file tree
Showing 57 changed files with 590 additions and 263 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptSettings;

import java.io.IOException;
import java.util.Objects;
Expand All @@ -42,11 +45,18 @@ public class QueryParseContext implements ParseFieldMatcherSupplier {
private final XContentParser parser;
private final IndicesQueriesRegistry indicesQueriesRegistry;
private final ParseFieldMatcher parseFieldMatcher;
private final String defaultScriptLanguage;

public QueryParseContext(IndicesQueriesRegistry registry, XContentParser parser, ParseFieldMatcher parseFieldMatcher) {
this(Script.DEFAULT_SCRIPT_LANG, registry, parser, parseFieldMatcher);
}

public QueryParseContext(String defaultScriptLanguage, IndicesQueriesRegistry registry, XContentParser parser,
ParseFieldMatcher parseFieldMatcher) {
this.indicesQueriesRegistry = Objects.requireNonNull(registry, "indices queries registry cannot be null");
this.parser = Objects.requireNonNull(parser, "parser cannot be null");
this.parseFieldMatcher = Objects.requireNonNull(parseFieldMatcher, "parse field matcher cannot be null");
this.defaultScriptLanguage = defaultScriptLanguage;
}

public XContentParser parser() {
Expand Down Expand Up @@ -127,4 +137,12 @@ public Optional<QueryBuilder> parseInnerQueryBuilder() throws IOException {
public ParseFieldMatcher getParseFieldMatcher() {
return parseFieldMatcher;
}

/**
* Returns the default scripting language, that should be used if scripts don't specify the script language
* explicitly.
*/
public String getDefaultScriptLanguage() {
return defaultScriptLanguage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;

/**
* Context object used to rewrite {@link QueryBuilder} instances into simplified version.
Expand Down Expand Up @@ -101,9 +102,18 @@ public ClusterState getClusterState() {

/**
* Returns a new {@link QueryParseContext} that wraps the provided parser, using the ParseFieldMatcher settings that
* are configured in the index settings
* are configured in the index settings. The default script language will always default to Painless.
*/
public QueryParseContext newParseContext(XContentParser parser) {
return new QueryParseContext(indicesQueriesRegistry, parser, indexSettings.getParseFieldMatcher());
}

/**
* Returns a new {@link QueryParseContext} like {@link #newParseContext(XContentParser)} with the only diffence, that
* the default script language will default to what has been set in the 'script.legacy.default_lang' setting.
*/
public QueryParseContext newParseContextWithLegacyScriptLanguage(XContentParser parser) {
String defaultScriptLanguage = ScriptSettings.getLegacyDefaultLang(indexSettings.getNodeSettings());
return new QueryParseContext(defaultScriptLanguage, indicesQueriesRegistry, parser, indexSettings.getParseFieldMatcher());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static Optional<ScriptQueryBuilder> fromXContent(QueryParseContext parseC
// skip
} else if (token == XContentParser.Token.START_OBJECT) {
if (parseContext.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
script = Script.parse(parser, parseContext.getParseFieldMatcher());
script = Script.parse(parser, parseContext.getParseFieldMatcher(), parseContext.getDefaultScriptLanguage());
} else {
throw new ParsingException(parser.getTokenLocation(), "[script] query does not support [" + currentFieldName + "]");
}
Expand All @@ -116,7 +116,7 @@ public static Optional<ScriptQueryBuilder> fromXContent(QueryParseContext parseC
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
boost = parser.floatValue();
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
script = Script.parse(parser, parseContext.getParseFieldMatcher());
script = Script.parse(parser, parseContext.getParseFieldMatcher(), parseContext.getDefaultScriptLanguage());
} else {
throw new ParsingException(parser.getTokenLocation(), "[script] query does not support [" + currentFieldName + "]");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public static ScriptScoreFunctionBuilder fromXContent(QueryParseContext parseCon
currentFieldName = parser.currentName();
} else {
if (parseContext.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
script = Script.parse(parser, parseContext.getParseFieldMatcher());
script = Script.parse(parser, parseContext.getParseFieldMatcher(), parseContext.getDefaultScriptLanguage());
} else {
throw new ParsingException(parser.getTokenLocation(), NAME + " query does not support [" + currentFieldName + "]");
}
Expand Down
11 changes: 6 additions & 5 deletions core/src/main/java/org/elasticsearch/script/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
public final class Script implements ToXContent, Writeable {

public static final ScriptType DEFAULT_TYPE = ScriptType.INLINE;
public static final String DEFAULT_SCRIPT_LANG = "painless";

private String script;
private ScriptType type;
Expand All @@ -60,7 +61,7 @@ public Script(String script) {
this(script, ScriptType.INLINE, null, null);
}

public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map<String, ?> params) {
public Script(String script, ScriptType type, String lang, @Nullable Map<String, ?> params) {
this(script, type, lang, params, null);
}

Expand All @@ -78,14 +79,14 @@ public Script(String script, ScriptType type, @Nullable String lang, @Nullable M
* when serializing the script back to xcontent.
*/
@SuppressWarnings("unchecked")
public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map<String, ?> params,
public Script(String script, ScriptType type, String lang, @Nullable Map<String, ?> params,
@Nullable XContentType contentType) {
if (contentType != null && type != ScriptType.INLINE) {
throw new IllegalArgumentException("The parameter contentType only makes sense for inline scripts");
}
this.script = Objects.requireNonNull(script);
this.type = Objects.requireNonNull(type);
this.lang = lang;
this.lang = lang == null ? DEFAULT_SCRIPT_LANG : lang;
this.params = (Map<String, Object>) params;
this.contentType = contentType;
}
Expand Down Expand Up @@ -135,7 +136,7 @@ public String getScript() {
* @return The type of script -- inline, stored, or file.
*/
public ScriptType getType() {
return type == null ? DEFAULT_TYPE : type;
return type;
}

/**
Expand Down Expand Up @@ -196,7 +197,7 @@ public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMa
token = parser.nextToken();
}
if (token == XContentParser.Token.VALUE_STRING) {
return new Script(parser.text());
return new Script(parser.text(), ScriptType.INLINE, lang, null);
}
if (token != XContentParser.Token.START_OBJECT) {
throw new ElasticsearchParseException("expected a string value or an object, but found [{}] instead", token);
Expand Down
16 changes: 3 additions & 13 deletions core/src/main/java/org/elasticsearch/script/ScriptService.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
public static final Setting<Integer> SCRIPT_MAX_COMPILATIONS_PER_MINUTE =
Setting.intSetting("script.max_compilations_per_minute", 15, 0, Property.Dynamic, Property.NodeScope);

private final String defaultLang;

private final Collection<ScriptEngineService> scriptEngines;
private final Map<String, ScriptEngineService> scriptEnginesByLang;
private final Map<String, ScriptEngineService> scriptEnginesByExt;
Expand Down Expand Up @@ -131,8 +129,6 @@ public ScriptService(Settings settings, Environment env,
this.scriptContextRegistry = scriptContextRegistry;
int cacheMaxSize = SCRIPT_CACHE_SIZE_SETTING.get(settings);

this.defaultLang = scriptSettings.getDefaultScriptLanguageSetting().get(settings);

CacheBuilder<CacheKey, CompiledScript> cacheBuilder = CacheBuilder.builder();
if (cacheMaxSize >= 0) {
cacheBuilder.setMaximumWeight(cacheMaxSize);
Expand Down Expand Up @@ -222,11 +218,6 @@ public CompiledScript compile(Script script, ScriptContext scriptContext, Map<St
}

String lang = script.getLang();

if (lang == null) {
lang = defaultLang;
}

ScriptEngineService scriptEngineService = getScriptEngineServiceForLang(lang);
if (canExecuteScript(lang, script.getType(), scriptContext) == false) {
throw new IllegalStateException("scripts of type [" + script.getType() + "], operation [" + scriptContext.getKey() + "] and lang [" + lang + "] are disabled");
Expand Down Expand Up @@ -285,7 +276,7 @@ CompiledScript compileInternal(Script script, Map<String, String> params) {
throw new IllegalArgumentException("The parameter script (Script) must not be null.");
}

String lang = script.getLang() == null ? defaultLang : script.getLang();
String lang = script.getLang();
ScriptType type = script.getType();
//script.getScript() could return either a name or code for a script,
//but we check for a file script name first and an indexed script name second
Expand Down Expand Up @@ -364,9 +355,8 @@ CompiledScript compileInternal(Script script, Map<String, String> params) {
}

private String validateScriptLanguage(String scriptLang) {
if (scriptLang == null) {
scriptLang = defaultLang;
} else if (scriptEnginesByLang.containsKey(scriptLang) == false) {
Objects.requireNonNull(scriptLang);
if (scriptEnginesByLang.containsKey(scriptLang) == false) {
throw new IllegalArgumentException("script_lang not supported [" + scriptLang + "]");
}
return scriptLang;
Expand Down
27 changes: 20 additions & 7 deletions core/src/main/java/org/elasticsearch/script/ScriptSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@

public class ScriptSettings {

public static final String DEFAULT_LANG = "painless";
static final String LEGACY_DEFAULT_LANG = "groovy";

/**
* The default script language to use for scripts that are stored in documents that have no script lang set explicitly.
* This setting is legacy setting and only applies for indices created on ES versions prior to version 5.0
*
* This constant will be removed in the next major release.
*/
@Deprecated
public static final String LEGACY_SCRIPT_SETTING = "script.legacy.default_lang";

private static final Map<ScriptService.ScriptType, Setting<Boolean>> SCRIPT_TYPE_SETTING_MAP;

Expand All @@ -49,7 +58,7 @@ public class ScriptSettings {

private final Map<ScriptContext, Setting<Boolean>> scriptContextSettingMap;
private final List<Setting<Boolean>> scriptLanguageSettings;
private final Setting<String> defaultScriptLanguageSetting;
private final Setting<String> defaultLegacyScriptLanguageSetting;

public ScriptSettings(ScriptEngineRegistry scriptEngineRegistry, ScriptContextRegistry scriptContextRegistry) {
Map<ScriptContext, Setting<Boolean>> scriptContextSettingMap = contextSettings(scriptContextRegistry);
Expand All @@ -58,8 +67,8 @@ public ScriptSettings(ScriptEngineRegistry scriptEngineRegistry, ScriptContextRe
List<Setting<Boolean>> scriptLanguageSettings = languageSettings(SCRIPT_TYPE_SETTING_MAP, scriptContextSettingMap, scriptEngineRegistry, scriptContextRegistry);
this.scriptLanguageSettings = Collections.unmodifiableList(scriptLanguageSettings);

this.defaultScriptLanguageSetting = new Setting<>("script.default_lang", DEFAULT_LANG, setting -> {
if (!DEFAULT_LANG.equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) {
this.defaultLegacyScriptLanguageSetting = new Setting<>(LEGACY_SCRIPT_SETTING, LEGACY_DEFAULT_LANG, setting -> {
if (!LEGACY_DEFAULT_LANG.equals(setting) && !scriptEngineRegistry.getRegisteredLanguages().containsKey(setting)) {
throw new IllegalArgumentException("unregistered default language [" + setting + "]");
}
return setting;
Expand Down Expand Up @@ -160,15 +169,19 @@ public List<Setting<?>> getSettings() {
settings.addAll(SCRIPT_TYPE_SETTING_MAP.values());
settings.addAll(scriptContextSettingMap.values());
settings.addAll(scriptLanguageSettings);
settings.add(defaultScriptLanguageSetting);
settings.add(defaultLegacyScriptLanguageSetting);
return settings;
}

public Iterable<Setting<Boolean>> getScriptLanguageSettings() {
return scriptLanguageSettings;
}

public Setting<String> getDefaultScriptLanguageSetting() {
return defaultScriptLanguageSetting;
public Setting<String> getDefaultLegacyScriptLanguageSetting() {
return defaultLegacyScriptLanguageSetting;
}

public static String getLegacyDefaultLang(Settings settings) {
return settings.get(LEGACY_SCRIPT_SETTING, ScriptSettings.LEGACY_DEFAULT_LANG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
package org.elasticsearch.search.aggregations.bucket.geogrid;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder;
import org.elasticsearch.search.aggregations.support.AbstractValuesSourceParser.GeoPointValuesSourceParser;
import org.elasticsearch.search.aggregations.support.XContentParseContext;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;

Expand Down Expand Up @@ -65,16 +65,17 @@ protected GeoGridAggregationBuilder createFactory(
}

@Override
protected boolean token(String aggregationName, String currentFieldName, Token token, XContentParser parser,
ParseFieldMatcher parseFieldMatcher, Map<ParseField, Object> otherOptions) throws IOException {
protected boolean token(String aggregationName, String currentFieldName, Token token,
XContentParseContext context, Map<ParseField, Object> otherOptions) throws IOException {
XContentParser parser = context.getParser();
if (token == XContentParser.Token.VALUE_NUMBER || token == XContentParser.Token.VALUE_STRING) {
if (parseFieldMatcher.match(currentFieldName, GeoHashGridParams.FIELD_PRECISION)) {
if (context.matchField(currentFieldName, GeoHashGridParams.FIELD_PRECISION)) {
otherOptions.put(GeoHashGridParams.FIELD_PRECISION, parser.intValue());
return true;
} else if (parseFieldMatcher.match(currentFieldName, GeoHashGridParams.FIELD_SIZE)) {
} else if (context.matchField(currentFieldName, GeoHashGridParams.FIELD_SIZE)) {
otherOptions.put(GeoHashGridParams.FIELD_SIZE, parser.intValue());
return true;
} else if (parseFieldMatcher.match(currentFieldName, GeoHashGridParams.FIELD_SHARD_SIZE)) {
} else if (context.matchField(currentFieldName, GeoHashGridParams.FIELD_SHARD_SIZE)) {
otherOptions.put(GeoHashGridParams.FIELD_SHARD_SIZE, parser.intValue());
return true;
}
Expand Down
Loading

0 comments on commit 245882c

Please sign in to comment.