From aeb97ff41298e26b107a733837dfe17f123c0c9b Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 10 Nov 2016 09:59:13 -0800 Subject: Clean up of Script. Closes #21321 --- .../org/elasticsearch/action/bulk/BulkRequest.java | 2 +- .../elasticsearch/action/update/UpdateHelper.java | 6 +- .../elasticsearch/action/update/UpdateRequest.java | 12 +- .../common/xcontent/ConstructingObjectParser.java | 2 +- .../common/xcontent/XContentParser.java | 4 + .../common/xcontent/XContentType.java | 8 +- .../xcontent/support/AbstractXContentParser.java | 46 ++ .../elasticsearch/index/query/InnerHitBuilder.java | 2 +- .../index/query/QueryRewriteContext.java | 3 +- .../index/query/QueryShardContext.java | 18 +- .../index/query/ScriptQueryBuilder.java | 12 +- .../functionscore/ScriptScoreFunctionBuilder.java | 8 +- .../ingest/InternalTemplateService.java | 2 +- .../main/java/org/elasticsearch/script/Script.java | 701 +++++++++++++++------ .../org/elasticsearch/script/ScriptService.java | 20 +- .../org/elasticsearch/search/SearchService.java | 3 +- .../significant/heuristics/ScriptHeuristic.java | 14 +- .../scripted/ScriptedMetricAggregationBuilder.java | 8 +- .../scripted/ScriptedMetricAggregatorFactory.java | 2 +- .../metrics/tophits/TopHitsAggregationBuilder.java | 2 +- .../BucketScriptPipelineAggregationBuilder.java | 9 +- .../BucketSelectorPipelineAggregationBuilder.java | 9 +- .../support/AbstractValuesSourceParser.java | 3 +- .../support/ValuesSourceAggregationBuilder.java | 2 +- .../search/sort/ScriptSortBuilder.java | 6 +- .../suggest/phrase/PhraseSuggestionBuilder.java | 4 +- 26 files changed, 630 insertions(+), 278 deletions(-) (limited to 'core/src/main/java/org/elasticsearch') diff --git a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java index 3910291326..ee4f96d484 100644 --- a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java +++ b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java @@ -170,7 +170,7 @@ public class BulkRequest extends ActionRequest implements Composite sizeInBytes += request.upsertRequest().source().length(); } if (request.script() != null) { - sizeInBytes += request.script().getScript().length() * 2; + sizeInBytes += request.script().getIdOrCode().length() * 2; } return this; } diff --git a/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java b/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java index 56d964362a..0e37b6ff06 100644 --- a/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java +++ b/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java @@ -116,7 +116,7 @@ public class UpdateHelper extends AbstractComponent { if (!"create".equals(scriptOpChoice)) { if (!"none".equals(scriptOpChoice)) { logger.warn("Used upsert operation [{}] for script [{}], doing nothing...", scriptOpChoice, - request.script.getScript()); + request.script.getIdOrCode()); } UpdateResponse update = new UpdateResponse(shardId, getResult.getType(), getResult.getId(), getResult.getVersion(), DocWriteResponse.Result.NOOP); @@ -242,7 +242,7 @@ public class UpdateHelper extends AbstractComponent { update.setGetResult(extractGetResult(request, request.index(), getResult.getVersion(), updatedSourceAsMap, updateSourceContentType, getResult.internalSourceRef())); return new Result(update, DocWriteResponse.Result.NOOP, updatedSourceAsMap, updateSourceContentType); } else { - logger.warn("Used update operation [{}] for script [{}], doing nothing...", operation, request.script.getScript()); + logger.warn("Used update operation [{}] for script [{}], doing nothing...", operation, request.script.getIdOrCode()); UpdateResponse update = new UpdateResponse(shardId, getResult.getType(), getResult.getId(), getResult.getVersion(), DocWriteResponse.Result.NOOP); return new Result(update, DocWriteResponse.Result.NOOP, updatedSourceAsMap, updateSourceContentType); } @@ -251,7 +251,7 @@ public class UpdateHelper extends AbstractComponent { private Map executeScript(Script script, Map ctx) { try { if (scriptService != null) { - ExecutableScript executableScript = scriptService.executable(script, ScriptContext.Standard.UPDATE, Collections.emptyMap()); + ExecutableScript executableScript = scriptService.executable(script, ScriptContext.Standard.UPDATE); executableScript.setNextVar("ctx", ctx); executableScript.run(); // we need to unwrap the ctx... diff --git a/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java b/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java index 54c435da36..f59fd142e7 100644 --- a/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java +++ b/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java @@ -224,7 +224,7 @@ public class UpdateRequest extends InstanceShardOperationRequest */ @Deprecated public String scriptString() { - return this.script == null ? null : this.script.getScript(); + return this.script == null ? null : this.script.getIdOrCode(); } /** @@ -327,13 +327,13 @@ public class UpdateRequest extends InstanceShardOperationRequest private void updateOrCreateScript(String scriptContent, ScriptType type, String lang, Map params) { Script script = script(); if (script == null) { - script = new Script(scriptContent == null ? "" : scriptContent, type == null ? ScriptType.INLINE : type, lang, params); + script = new Script(type == null ? ScriptType.INLINE : type, lang, scriptContent == null ? "" : scriptContent, params); } else { - String newScriptContent = scriptContent == null ? script.getScript() : scriptContent; + String newScriptContent = scriptContent == null ? script.getIdOrCode() : scriptContent; ScriptType newScriptType = type == null ? script.getType() : type; String newScriptLang = lang == null ? script.getLang() : lang; Map newScriptParams = params == null ? script.getParams() : params; - script = new Script(newScriptContent, newScriptType, newScriptLang, newScriptParams); + script = new Script(newScriptType, newScriptLang, newScriptContent, newScriptParams); } script(script); } @@ -347,7 +347,7 @@ public class UpdateRequest extends InstanceShardOperationRequest */ @Deprecated public UpdateRequest script(String script, ScriptType scriptType, @Nullable Map scriptParams) { - this.script = new Script(script, scriptType, null, scriptParams); + this.script = new Script(scriptType, Script.DEFAULT_SCRIPT_LANG, script, scriptParams); return this; } @@ -370,7 +370,7 @@ public class UpdateRequest extends InstanceShardOperationRequest @Deprecated public UpdateRequest script(String script, @Nullable String scriptLang, ScriptType scriptType, @Nullable Map scriptParams) { - this.script = new Script(script, scriptType, scriptLang, scriptParams); + this.script = new Script(scriptType, scriptLang, script, scriptParams); return this; } diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/ConstructingObjectParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/ConstructingObjectParser.java index b8a42cd1e1..1d30b79e29 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/ConstructingObjectParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/ConstructingObjectParser.java @@ -297,7 +297,7 @@ public final class ConstructingObjectParser mapOrdered() throws IOException; + Map mapStrings() throws IOException; + + Map mapStringsOrdered() throws IOException; + List list() throws IOException; List listOrderedMap() throws IOException; diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java index 296f9d2aed..ddd736e0d0 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java @@ -21,6 +21,7 @@ package org.elasticsearch.common.xcontent; 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.xcontent.cbor.CborXContent; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.smile.SmileXContent; @@ -32,7 +33,7 @@ import java.util.Locale; /** * The content type of {@link org.elasticsearch.common.xcontent.XContent}. */ -public enum XContentType { +public enum XContentType implements Writeable { /** * A JSON based content type. @@ -168,7 +169,8 @@ public enum XContentType { throw new IllegalStateException("Unknown XContentType with index [" + index + "]"); } - public static void writeTo(XContentType contentType, StreamOutput out) throws IOException { - out.writeVInt(contentType.index); + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(index); } } diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java index c002549944..d13dcbd9c9 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java @@ -215,6 +215,16 @@ public abstract class AbstractXContentParser implements XContentParser { return readOrderedMap(this); } + @Override + public Map mapStrings() throws IOException { + return readMapStrings(this); + } + + @Override + public Map mapStringsOrdered() throws IOException { + return readOrderedMapStrings(this); + } + @Override public List list() throws IOException { return readList(this); @@ -229,10 +239,18 @@ public abstract class AbstractXContentParser implements XContentParser { Map newMap(); } + interface MapStringsFactory { + Map newMap(); + } + static final MapFactory SIMPLE_MAP_FACTORY = HashMap::new; static final MapFactory ORDERED_MAP_FACTORY = LinkedHashMap::new; + static final MapStringsFactory SIMPLE_MAP_STRINGS_FACTORY = HashMap::new; + + static final MapStringsFactory ORDERED_MAP_STRINGS_FACTORY = LinkedHashMap::new; + static Map readMap(XContentParser parser) throws IOException { return readMap(parser, SIMPLE_MAP_FACTORY); } @@ -241,6 +259,14 @@ public abstract class AbstractXContentParser implements XContentParser { return readMap(parser, ORDERED_MAP_FACTORY); } + static Map readMapStrings(XContentParser parser) throws IOException { + return readMapStrings(parser, SIMPLE_MAP_STRINGS_FACTORY); + } + + static Map readOrderedMapStrings(XContentParser parser) throws IOException { + return readMapStrings(parser, ORDERED_MAP_STRINGS_FACTORY); + } + static List readList(XContentParser parser) throws IOException { return readList(parser, SIMPLE_MAP_FACTORY); } @@ -269,6 +295,26 @@ public abstract class AbstractXContentParser implements XContentParser { return map; } + static Map readMapStrings(XContentParser parser, MapStringsFactory mapStringsFactory) throws IOException { + Map map = mapStringsFactory.newMap(); + XContentParser.Token token = parser.currentToken(); + if (token == null) { + token = parser.nextToken(); + } + if (token == XContentParser.Token.START_OBJECT) { + token = parser.nextToken(); + } + for (; token == XContentParser.Token.FIELD_NAME; token = parser.nextToken()) { + // Must point to field name + String fieldName = parser.currentName(); + // And then the value... + parser.nextToken(); + String value = parser.text(); + map.put(fieldName, value); + } + return map; + } + static List readList(XContentParser parser, MapFactory mapFactory) throws IOException { XContentParser.Token token = parser.currentToken(); if (token == null) { diff --git a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java index f2c83ce2a7..3a98ba36d2 100644 --- a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java @@ -576,7 +576,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl if (scriptFields != null) { for (ScriptField field : scriptFields) { SearchScript searchScript = innerHitsContext.getQueryShardContext().getSearchScript(field.script(), - ScriptContext.Standard.SEARCH, Collections.emptyMap()); + ScriptContext.Standard.SEARCH); innerHitsContext.scriptFields().add(new org.elasticsearch.search.fetch.subphase.ScriptFieldsContext.ScriptField( field.fieldName(), searchScript, field.ignoreFailure())); } diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java b/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java index b569c36ed8..26c1523027 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java @@ -127,8 +127,7 @@ public class QueryRewriteContext implements ParseFieldMatcherSupplier { } public BytesReference getTemplateBytes(Script template) { - ExecutableScript executable = scriptService.executable(template, - ScriptContext.Standard.SEARCH, Collections.emptyMap()); + ExecutableScript executable = scriptService.executable(template, ScriptContext.Standard.SEARCH); return (BytesReference) executable.run(); } diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java index 7c9d958e2e..df54234591 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -338,18 +338,17 @@ public class QueryShardContext extends QueryRewriteContext { * Compiles (or retrieves from cache) and binds the parameters to the * provided script */ - public final SearchScript getSearchScript(Script script, ScriptContext context, Map params) { + public final SearchScript getSearchScript(Script script, ScriptContext context) { failIfFrozen(); - return scriptService.search(lookup(), script, context, params); + return scriptService.search(lookup(), script, context); } /** * Returns a lazily created {@link SearchScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public final Function, SearchScript> getLazySearchScript(Script script, ScriptContext context, - Map params) { + public final Function, SearchScript> getLazySearchScript(Script script, ScriptContext context) { failIfFrozen(); - CompiledScript compile = scriptService.compile(script, context, params); + CompiledScript compile = scriptService.compile(script, context, script.getOptions()); return (p) -> scriptService.search(lookup(), compile, p); } @@ -357,19 +356,18 @@ public class QueryShardContext extends QueryRewriteContext { * Compiles (or retrieves from cache) and binds the parameters to the * provided script */ - public final ExecutableScript getExecutableScript(Script script, ScriptContext context, Map params) { + public final ExecutableScript getExecutableScript(Script script, ScriptContext context) { failIfFrozen(); - return scriptService.executable(script, context, params); + return scriptService.executable(script, context); } /** * Returns a lazily created {@link ExecutableScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public final Function, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context, - Map params) { + public final Function, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context) { failIfFrozen(); - CompiledScript executable = scriptService.compile(script, context, params); + CompiledScript executable = scriptService.compile(script, context, script.getOptions()); return (p) -> scriptService.executable(executable, p); } diff --git a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java index 01f29614e2..444d79491c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java @@ -33,14 +33,10 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.Script; -import org.elasticsearch.script.Script.ScriptField; import org.elasticsearch.script.ScriptContext; -import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.SearchScript; -import org.elasticsearch.search.lookup.SearchLookup; import java.io.IOException; -import java.util.Collections; import java.util.Objects; import java.util.Optional; @@ -83,7 +79,7 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder @Override protected void doXContent(XContentBuilder builder, Params builderParams) throws IOException { builder.startObject(NAME); - builder.field(ScriptField.SCRIPT.getPreferredName(), script); + builder.field(Script.SCRIPT_PARSE_FIELD.getPreferredName(), script); printBoostAndQueryName(builder); builder.endObject(); } @@ -104,7 +100,7 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder } else if (parseContext.isDeprecatedSetting(currentFieldName)) { // skip } else if (token == XContentParser.Token.START_OBJECT) { - if (parseContext.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) { + if (parseContext.getParseFieldMatcher().match(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, parseContext.getParseFieldMatcher(), parseContext.getDefaultScriptLanguage()); } else { throw new ParsingException(parser.getTokenLocation(), "[script] query does not support [" + currentFieldName + "]"); @@ -114,7 +110,7 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder queryName = parser.text(); } else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) { boost = parser.floatValue(); - } else if (parseContext.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) { + } else if (parseContext.getParseFieldMatcher().match(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, parseContext.getParseFieldMatcher(), parseContext.getDefaultScriptLanguage()); } else { throw new ParsingException(parser.getTokenLocation(), "[script] query does not support [" + currentFieldName + "]"); @@ -133,7 +129,7 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder @Override protected Query doToQuery(QueryShardContext context) throws IOException { - return new ScriptQuery(script, context.getSearchScript(script, ScriptContext.Standard.SEARCH, Collections.emptyMap())); + return new ScriptQuery(script, context.getSearchScript(script, ScriptContext.Standard.SEARCH)); } static class ScriptQuery extends Query { diff --git a/core/src/main/java/org/elasticsearch/index/query/functionscore/ScriptScoreFunctionBuilder.java b/core/src/main/java/org/elasticsearch/index/query/functionscore/ScriptScoreFunctionBuilder.java index 77923df09b..8a5e950432 100644 --- a/core/src/main/java/org/elasticsearch/index/query/functionscore/ScriptScoreFunctionBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/functionscore/ScriptScoreFunctionBuilder.java @@ -30,12 +30,10 @@ import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.script.Script; -import org.elasticsearch.script.Script.ScriptField; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.SearchScript; import java.io.IOException; -import java.util.Collections; import java.util.Objects; /** @@ -74,7 +72,7 @@ public class ScriptScoreFunctionBuilder extends ScoreFunctionBuilder params; - @Nullable private XContentType contentType; + /** + * The name of the default template language. + */ + public static final String DEFAULT_TEMPLATE_LANG = "mustache"; /** - * Constructor for simple inline script. The script will have no lang or params set. - * - * @param script The inline script to execute. + * The default {@link ScriptType}. */ - public Script(String script) { - this(script, ScriptType.INLINE, null, null); - } + public static final ScriptType DEFAULT_SCRIPT_TYPE = ScriptType.INLINE; - public Script(String script, ScriptType type, String lang, @Nullable Map params) { - this(script, type, lang, params, null); - } + /** + * Compiler option for {@link XContentType} used for templates. + */ + public static final String CONTENT_TYPE_OPTION = "content_type"; /** - * Constructor for Script. - * - * @param script The cache key of the script to be compiled/executed. For inline scripts this is the actual - * script source code. For indexed scripts this is the id used in the request. For on file - * scripts this is the file name. - * @param type The type of script -- dynamic, stored, or file. - * @param lang The language of the script to be compiled/executed. - * @param params The map of parameters the script will be executed with. - * @param contentType The {@link XContentType} of the script. Only relevant for inline scripts that have not been - * defined as a plain string, but as json or yaml content. This class needs this information - * when serializing the script back to xcontent. + * Standard {@link ParseField} for outer level of script queries. + */ + public static final ParseField SCRIPT_PARSE_FIELD = new ParseField("script"); + + /** + * Standard {@link ParseField} for lang on the inner level. + */ + public static final ParseField LANG_PARSE_FIELD = new ParseField("lang"); + + /** + * Standard {@link ParseField} for options on the inner level. + */ + public static final ParseField OPTIONS_PARSE_FIELD = new ParseField("options"); + + /** + * Standard {@link ParseField} for params on the inner level. + */ + public static final ParseField PARAMS_PARSE_FIELD = new ParseField("params"); + + /** + * Unreleased version used for {@link Script} non-null members format of read/write. + */ + public static final Version V_5_1_0_UNRELEASED = Version.fromId(5010099); + + /** + * Helper class used by {@link ObjectParser} to store mutable {@link Script} variables and then + * construct an immutable {@link Script} object based on parsed XContent. */ - @SuppressWarnings("unchecked") - public Script(String script, ScriptType type, String lang, @Nullable Map params, - @Nullable XContentType contentType) { - if (contentType != null && type != ScriptType.INLINE) { - throw new IllegalArgumentException("The parameter contentType only makes sense for inline scripts"); + private static final class Builder { + private ScriptType type; + private String lang; + private String idOrCode; + private Map options; + private Map params; + + private Builder() { + // This cannot default to an empty map because options are potentially added at multiple points. + this.options = new HashMap<>(); + this.params = Collections.emptyMap(); } - this.script = Objects.requireNonNull(script); - this.type = Objects.requireNonNull(type); - this.lang = lang == null ? DEFAULT_SCRIPT_LANG : lang; - this.params = (Map) params; - this.contentType = contentType; - } - public Script(StreamInput in) throws IOException { - script = in.readString(); - if (in.readBoolean()) { - type = ScriptType.readFrom(in); + /** + * Since inline scripts can accept code rather than just an id, they must also be able + * to handle template parsing, hence the need for custom parsing code. Templates can + * consist of either an {@link String} or a JSON object. If a JSON object is discovered + * then the content type option must also be saved as a compiler option. + */ + private void setInline(XContentParser parser) { + try { + if (type != null) { + throwOnlyOneOfType(); + } + + type = ScriptType.INLINE; + + if (parser.currentToken() == Token.START_OBJECT) { + XContentBuilder builder = XContentFactory.contentBuilder(parser.contentType()); + idOrCode = builder.copyCurrentStructure(parser).bytes().utf8ToString(); + options.put(CONTENT_TYPE_OPTION, parser.contentType().mediaType()); + } else { + idOrCode = parser.text(); + } + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } } - lang = in.readOptionalString(); - params = in.readMap(); - if (in.readBoolean()) { - contentType = XContentType.readFrom(in); + + /** + * Set both the id and the type of the stored script. + */ + private void setStored(String idOrCode) { + if (type != null) { + throwOnlyOneOfType(); + } + + type = ScriptType.STORED; + this.idOrCode = idOrCode; } - } - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(script); - boolean hasType = type != null; - out.writeBoolean(hasType); - if (hasType) { - type.writeTo(out); + /** + * Set both the id and the type of the file script. + */ + private void setFile(String idOrCode) { + if (type != null) { + throwOnlyOneOfType(); + } + + type = ScriptType.FILE; + this.idOrCode = idOrCode; } - out.writeOptionalString(lang); - out.writeMap(params); - boolean hasContentType = contentType != null; - out.writeBoolean(hasContentType); - if (hasContentType) { - XContentType.writeTo(contentType, out); + + /** + * Helper method to throw an exception if more than one type of {@link Script} is specified. + */ + private void throwOnlyOneOfType() { + throw new IllegalArgumentException("must only use one of [" + + ScriptType.INLINE.getParseField().getPreferredName() + " + , " + + ScriptType.STORED.getParseField().getPreferredName() + " + , " + + ScriptType.FILE.getParseField().getPreferredName() + "]" + + " when specifying a script"); + } + + private void setLang(String lang) { + this.lang = lang; + } + + /** + * Options may have already been added if an inline template was specified. + * Appends the user-defined compiler options with the internal compiler options. + */ + private void setOptions(Map options) { + this.options.putAll(options); + } + + private void setParams(Map params) { + this.params = params; + } + + /** + * Validates the parameters and creates an {@link Script}. + * @param defaultLang The default lang is not a compile-time constant and must be provided + * at run-time this way in case a legacy default language is used from + * previously stored queries. + */ + private Script build(String defaultLang) { + if (type == null) { + throw new IllegalArgumentException( + "must specify either code for an [" + ScriptType.INLINE.getParseField().getPreferredName() + "] script " + + "or an id for a [" + ScriptType.STORED.getParseField().getPreferredName() + "] script " + + "or [" + ScriptType.FILE.getParseField().getPreferredName() + "] script"); + } + + if (idOrCode == null) { + throw new IllegalArgumentException("must specify an id or code for a script"); + } + + if (options.size() > 1 || options.size() == 1 && options.get(CONTENT_TYPE_OPTION) == null) { + throw new IllegalArgumentException("illegal compiler options [" + options + "] specified"); + } + + return new Script(type, this.lang == null ? defaultLang : this.lang, idOrCode, options, params); } } + private static final ObjectParser PARSER = new ObjectParser<>("script", Builder::new); + + static { + // Defines the fields necessary to parse a Script as XContent using an ObjectParser. + PARSER.declareField(Builder::setInline, parser -> parser, ScriptType.INLINE.getParseField(), ValueType.OBJECT_OR_STRING); + PARSER.declareString(Builder::setStored, ScriptType.STORED.getParseField()); + PARSER.declareString(Builder::setFile, ScriptType.FILE.getParseField()); + PARSER.declareString(Builder::setLang, LANG_PARSE_FIELD); + PARSER.declareField(Builder::setOptions, XContentParser::mapStrings, OPTIONS_PARSE_FIELD, ValueType.OBJECT); + PARSER.declareField(Builder::setParams, XContentParser::map, PARAMS_PARSE_FIELD, ValueType.OBJECT); + } + /** - * Method for getting the script. - * @return The cache key of the script to be compiled/executed. For dynamic scripts this is the actual - * script source code. For indexed scripts this is the id used in the request. For on disk scripts - * this is the file name. + * Convenience method to call {@link Script#parse(XContentParser, ParseFieldMatcher, String)} + * using the default scripting language. */ - public String getScript() { - return script; + public static Script parse(XContentParser parser, ParseFieldMatcher matcher) throws IOException { + return parse(parser, matcher, DEFAULT_SCRIPT_LANG); } /** - * Method for getting the type. - * - * @return The type of script -- inline, stored, or file. + * Convenience method to call {@link Script#parse(XContentParser, ParseFieldMatcher, String)} using the + * {@link ParseFieldMatcher} and scripting language provided by the {@link QueryParseContext}. */ - public ScriptType getType() { - return type; + public static Script parse(XContentParser parser, QueryParseContext context) throws IOException { + return parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); } /** - * Method for getting language. + * This will parse XContent into a {@link Script}. The following formats can be parsed: + * + * The simple format defaults to an {@link ScriptType#INLINE} with no compiler options or user-defined params: + * + * Example: + * {@code + * "return Math.log(doc.popularity) * 100;" + * } + * + * The complex format where {@link ScriptType} and idOrCode are required while lang, options and params are not required. + * + * {@code + * { + * "" : "", + * "lang" : "", + * "options" : { + * "option0" : "", + * "option1" : "", + * ... + * }, + * "params" : { + * "param0" : "", + * "param1" : "", + * ... + * } + * } + * } + * + * Example: + * {@code + * { + * "inline" : "return Math.log(doc.popularity) * params.multiplier", + * "lang" : "painless", + * "params" : { + * "multiplier" : 100.0 + * } + * } + * } + * + * This also handles templates in a special way. If a complexly formatted query is specified as another complex + * JSON object the query is assumed to be a template, and the format will be preserved. * - * @return The language of the script to be compiled/executed. + * {@code + * { + * "inline" : { "query" : ... }, + * "lang" : "", + * "options" : { + * "option0" : "", + * "option1" : "", + * ... + * }, + * "params" : { + * "param0" : "", + * "param1" : "", + * ... + * } + * } + * } + * + * @param parser The {@link XContentParser} to be used. + * @param matcher The {@link ParseFieldMatcher} to be used. + * @param defaultLang The default language to use if no language is specified. The default language isn't necessarily + * the one defined by {@link Script#DEFAULT_SCRIPT_LANG} due to backwards compatiblity requirements + * related to stored queries using previously default languauges. + * @return The parsed {@link Script}. */ - public String getLang() { - return lang; + public static Script parse(XContentParser parser, ParseFieldMatcher matcher, String defaultLang) throws IOException { + Objects.requireNonNull(defaultLang); + + Token token = parser.currentToken(); + + if (token == null) { + token = parser.nextToken(); + } + + if (token == Token.VALUE_STRING) { + return new Script(ScriptType.INLINE, defaultLang, parser.text(), Collections.emptyMap()); + } + + return PARSER.apply(parser, () -> matcher).build(defaultLang); } + private final ScriptType type; + private final String lang; + private final String idOrCode; + private final Map options; + private final Map params; + /** - * Method for getting the parameters. - * - * @return The map of parameters the script will be executed with. + * Constructor for simple script using the default language and default type. + * @param idOrCode The id or code to use dependent on the default script type. */ - public Map getParams() { - return params; + public Script(String idOrCode) { + this(DEFAULT_SCRIPT_TYPE, DEFAULT_SCRIPT_LANG, idOrCode, Collections.emptyMap(), Collections.emptyMap()); } /** - * @return The content type of the script if it is an inline script and the script has been defined as json - * or yaml content instead of a plain string. + * Constructor for a script that does not need to use compiler options. + * @param type The {@link ScriptType}. + * @param lang The lang for this {@link Script}. + * @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}. + * The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}. + * @param params The user-defined params to be bound for script execution. */ - public XContentType getContentType() { - return contentType; + public Script(ScriptType type, String lang, String idOrCode, Map params) { + this(type, lang, idOrCode, Collections.emptyMap(), params); + } + + /** + * Constructor for a script that requires the use of compiler options. + * @param type The {@link ScriptType}. + * @param lang The lang for this {@link Script}. + * @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}. + * The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}. + * @param options The options to be passed to the compiler for use at compile-time. + * @param params The user-defined params to be bound for script execution. + */ + public Script(ScriptType type, String lang, String idOrCode, Map options, Map params) { + this.idOrCode = Objects.requireNonNull(idOrCode); + this.type = Objects.requireNonNull(type); + this.lang = Objects.requireNonNull(lang); + this.options = Collections.unmodifiableMap(Objects.requireNonNull(options)); + this.params = Collections.unmodifiableMap(Objects.requireNonNull(params)); + + if (type != ScriptType.INLINE && !options.isEmpty()) { + throw new IllegalArgumentException( + "Compiler options [" + options + "] cannot be specified at runtime for [" + type + "] scripts."); + } + } + + /** + * Creates a {@link Script} read from an input stream. + */ + public Script(StreamInput in) throws IOException { + // Version 5.1+ requires all Script members to be non-null and supports the potential + // for more options than just XContentType. Reorders the read in contents to be in + // same order as the constructor. + if (in.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) { + this.type = ScriptType.readFrom(in); + this.lang = in.readString(); + this.idOrCode = in.readString(); + @SuppressWarnings("unchecked") + Map options = (Map)(Map)in.readMap(); + this.options = options; + this.params = in.readMap(); + // Prior to version 5.1 the script members are read in certain cases as optional and given + // default values when necessary. Also the only option supported is for XContentType. + } else { + String idOrCode = in.readString(); + ScriptType type; + + if (in.readBoolean()) { + type = ScriptType.readFrom(in); + } else { + type = DEFAULT_SCRIPT_TYPE; + } + + String lang = in.readOptionalString(); + + if (lang == null) { + lang = DEFAULT_SCRIPT_LANG; + } + + Map params = in.readMap(); + + if (params == null) { + params = new HashMap<>(); + } + + Map options = new HashMap<>(); + + if (in.readBoolean()) { + XContentType contentType = XContentType.readFrom(in); + options.put(CONTENT_TYPE_OPTION, contentType.mediaType()); + } + + this.type = type; + this.lang = lang; + this.idOrCode = idOrCode; + this.options = options; + this.params = params; + } } @Override - public XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException { - if (type == null) { - return builder.value(script); + public void writeTo(StreamOutput out) throws IOException { + // Version 5.1+ requires all Script members to be non-null and supports the potential + // for more options than just XContentType. Reorders the written out contents to be in + // same order as the constructor. + if (out.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) { + type.writeTo(out); + out.writeString(lang); + out.writeString(idOrCode); + @SuppressWarnings("unchecked") + Map options = (Map)(Map)this.options; + out.writeMap(options); + out.writeMap(params); + // Prior to version 5.1 the Script members were possibly written as optional or null, though this is no longer + // necessary since Script members cannot be null anymore, and there is no case where a null value wasn't equivalent + // to it's default value when actually compiling/executing a script. Meaning, there are no backwards compatibility issues, + // and now there's enforced consistency. Also the only supported compiler option was XContentType. + } else { + out.writeString(idOrCode); + out.writeBoolean(true); + type.writeTo(out); + out.writeBoolean(true); + out.writeString(lang); + out.writeMap(params.isEmpty() ? null : params); + + if (options.containsKey(CONTENT_TYPE_OPTION)) { + XContentType contentType = XContentType.fromMediaTypeOrFormat(options.get(CONTENT_TYPE_OPTION)); + out.writeBoolean(true); + contentType.writeTo(out); + } else { + out.writeBoolean(false); + } } + } + + /** + * This will build scripts into the following XContent structure: + * + * {@code + * { + * "" : "", + * "lang" : "", + * "options" : { + * "option0" : "", + * "option1" : "", + * ... + * }, + * "params" : { + * "param0" : "", + * "param1" : "", + * ... + * } + * } + * } + * + * Example: + * {@code + * { + * "inline" : "return Math.log(doc.popularity) * params.multiplier;", + * "lang" : "painless", + * "params" : { + * "multiplier" : 100.0 + * } + * } + * } + * + * Note that options and params will only be included if there have been any specified. + * + * This also handles templates in a special way. If the {@link Script#CONTENT_TYPE_OPTION} option + * is provided and the {@link ScriptType#INLINE} is specified then the template will be preserved as a raw field. + * + * {@code + * { + * "inline" : { "query" : ... }, + * "lang" : "", + * "options" : { + * "option0" : "", + * "option1" : "", + * ... + * }, + * "params" : { + * "param0" : "", + * "param1" : "", + * ... + * } + * } + * } + */ + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException { builder.startObject(); - if (type == ScriptType.INLINE && contentType != null && builder.contentType() == contentType) { - builder.rawField(type.getParseField().getPreferredName(), new BytesArray(script)); + + String contentType = options.get(CONTENT_TYPE_OPTION); + + if (type == ScriptType.INLINE && contentType != null && builder.contentType().mediaType().equals(contentType)) { + builder.rawField(type.getParseField().getPreferredName(), new BytesArray(idOrCode)); } else { - builder.field(type.getParseField().getPreferredName(), script); + builder.field(type.getParseField().getPreferredName(), idOrCode); } - if (lang != null) { - builder.field(ScriptField.LANG.getPreferredName(), lang); + + builder.field(LANG_PARSE_FIELD.getPreferredName(), lang); + + if (!options.isEmpty()) { + builder.field(OPTIONS_PARSE_FIELD.getPreferredName(), options); } - if (params != null) { - builder.field(ScriptField.PARAMS.getPreferredName(), params); + + if (!params.isEmpty()) { + builder.field(PARAMS_PARSE_FIELD.getPreferredName(), params); } + builder.endObject(); + return builder; } - public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException { - return parse(parser, parseFieldMatcher, null); + /** + * @return The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}. + * The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}. + */ + public String getIdOrCode() { + return idOrCode; + } + + /** + * @return The {@link ScriptType} for this {@link Script}. + */ + public ScriptType getType() { + return type; } - public static Script parse(XContentParser parser, QueryParseContext context) { - try { - return parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); - } catch (IOException e) { - throw new ParsingException(parser.getTokenLocation(), "Error parsing [" + ScriptField.SCRIPT.getPreferredName() + "] field", e); - } + /** + * @return The language for this {@link Script}. + */ + public String getLang() { + return lang; } - public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher, @Nullable String lang) throws IOException { - XContentParser.Token token = parser.currentToken(); - // If the parser hasn't yet been pushed to the first token, do it now - if (token == null) { - token = parser.nextToken(); - } - if (token == XContentParser.Token.VALUE_STRING) { - 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); - } - String script = null; - ScriptType type = null; - Map params = null; - XContentType contentType = null; - String cfn = null; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - cfn = parser.currentName(); - } else if (parseFieldMatcher.match(cfn, ScriptType.INLINE.getParseField())) { - type = ScriptType.INLINE; - if (parser.currentToken() == XContentParser.Token.START_OBJECT) { - contentType = parser.contentType(); - XContentBuilder builder = XContentFactory.contentBuilder(contentType); - script = builder.copyCurrentStructure(parser).bytes().utf8ToString(); - } else { - script = parser.text(); - } - } else if (parseFieldMatcher.match(cfn, ScriptType.FILE.getParseField())) { - type = ScriptType.FILE; - if (token == XContentParser.Token.VALUE_STRING) { - script = parser.text(); - } else { - throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token); - } - } else if (parseFieldMatcher.match(cfn, ScriptType.STORED.getParseField())) { - type = ScriptType.STORED; - if (token == XContentParser.Token.VALUE_STRING) { - script = parser.text(); - } else { - throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token); - } - } else if (parseFieldMatcher.match(cfn, ScriptField.LANG)) { - if (token == XContentParser.Token.VALUE_STRING) { - lang = parser.text(); - } else { - throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token); - } - } else if (parseFieldMatcher.match(cfn, ScriptField.PARAMS)) { - if (token == XContentParser.Token.START_OBJECT) { - params = parser.map(); - } else { - throw new ElasticsearchParseException("expected an object for field [{}], but found [{}]", cfn, token); - } - } else { - throw new ElasticsearchParseException("unexpected field [{}]", cfn); - } - } - if (script == null) { - throw new ElasticsearchParseException("expected one of [{}], [{}] or [{}] fields, but found none", - ScriptType.INLINE.getParseField() .getPreferredName(), ScriptType.FILE.getParseField().getPreferredName(), - ScriptType.STORED.getParseField() .getPreferredName()); - } - return new Script(script, type, lang, params, contentType); + /** + * @return The map of compiler options for this {@link Script}. + */ + public Map getOptions() { + return options; } - @Override - public int hashCode() { - return Objects.hash(lang, params, script, type, contentType); + /** + * @return The map of user-defined params for this {@link Script}. + */ + public Map getParams() { + return params; } @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Script other = (Script) obj; - - return Objects.equals(lang, other.lang) && - Objects.equals(params, other.params) && - Objects.equals(script, other.script) && - Objects.equals(type, other.type) && - Objects.equals(contentType, other.contentType); + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Script script = (Script)o; + + if (type != script.type) return false; + if (!lang.equals(script.lang)) return false; + if (!idOrCode.equals(script.idOrCode)) return false; + if (!options.equals(script.options)) return false; + return params.equals(script.params); + } @Override - public String toString() { - return "[script: " + script + ", type: " + type.getParseField().getPreferredName() + ", lang: " - + lang + ", params: " + params + "]"; + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + lang.hashCode(); + result = 31 * result + idOrCode.hashCode(); + result = 31 * result + options.hashCode(); + result = 31 * result + params.hashCode(); + return result; } - public interface ScriptField { - ParseField SCRIPT = new ParseField("script"); - ParseField LANG = new ParseField("lang"); - ParseField PARAMS = new ParseField("params"); + @Override + public String toString() { + return "Script{" + + "type=" + type + + ", lang='" + lang + '\'' + + ", idOrCode='" + idOrCode + '\'' + + ", options=" + options + + ", params=" + params + + '}'; } - } diff --git a/core/src/main/java/org/elasticsearch/script/ScriptService.java b/core/src/main/java/org/elasticsearch/script/ScriptService.java index f38a213123..1dc1cda0ad 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptService.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptService.java @@ -274,9 +274,9 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust String lang = script.getLang(); ScriptType type = script.getType(); - //script.getScript() could return either a name or code for a script, + //script.getIdOrCode() 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 - String name = script.getScript(); + String name = script.getIdOrCode(); if (logger.isTraceEnabled()) { logger.trace("Compiling lang: [{}] type: [{}] script: {}", lang, type, name); @@ -296,8 +296,8 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust return compiledScript; } - //script.getScript() will be code if the script type is inline - String code = script.getScript(); + //script.getIdOrCode() will be code if the script type is inline + String code = script.getIdOrCode(); if (type == ScriptType.STORED) { //The look up for an indexed script must be done every time in case @@ -468,22 +468,22 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust /** * Compiles (or retrieves from cache) and executes the provided script */ - public ExecutableScript executable(Script script, ScriptContext scriptContext, Map params) { - return executable(compile(script, scriptContext, params), script.getParams()); + public ExecutableScript executable(Script script, ScriptContext scriptContext) { + return executable(compile(script, scriptContext, script.getOptions()), script.getParams()); } /** * Executes a previously compiled script provided as an argument */ - public ExecutableScript executable(CompiledScript compiledScript, Map vars) { - return getScriptEngineServiceForLang(compiledScript.lang()).executable(compiledScript, vars); + public ExecutableScript executable(CompiledScript compiledScript, Map params) { + return getScriptEngineServiceForLang(compiledScript.lang()).executable(compiledScript, params); } /** * Compiles (or retrieves from cache) and executes the provided search script */ - public SearchScript search(SearchLookup lookup, Script script, ScriptContext scriptContext, Map params) { - CompiledScript compiledScript = compile(script, scriptContext, params); + public SearchScript search(SearchLookup lookup, Script script, ScriptContext scriptContext) { + CompiledScript compiledScript = compile(script, scriptContext, script.getOptions()); return search(lookup, compiledScript, script.getParams()); } diff --git a/core/src/main/java/org/elasticsearch/search/SearchService.java b/core/src/main/java/org/elasticsearch/search/SearchService.java index d6ef1e0c54..9666df8cc5 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchService.java +++ b/core/src/main/java/org/elasticsearch/search/SearchService.java @@ -769,8 +769,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv } if (source.scriptFields() != null) { for (org.elasticsearch.search.builder.SearchSourceBuilder.ScriptField field : source.scriptFields()) { - SearchScript searchScript = scriptService.search(context.lookup(), field.script(), ScriptContext.Standard.SEARCH, - Collections.emptyMap()); + SearchScript searchScript = scriptService.search(context.lookup(), field.script(), ScriptContext.Standard.SEARCH); context.scriptFields().add(new ScriptField(field.fieldName(), searchScript, field.ignoreFailure())); } } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/heuristics/ScriptHeuristic.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/heuristics/ScriptHeuristic.java index 748adb67ce..9519a95d3a 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/heuristics/ScriptHeuristic.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/heuristics/ScriptHeuristic.java @@ -29,21 +29,19 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; -import org.elasticsearch.script.Script.ScriptField; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.support.XContentParseContext; import org.elasticsearch.search.internal.SearchContext; import java.io.IOException; -import java.util.Collections; import java.util.Objects; public class ScriptHeuristic extends SignificanceHeuristic { public static final String NAME = "script_heuristic"; private final Script script; - + // This class holds an executable form of the script with private variables ready for execution // on a single search thread. static class ExecutableScriptHeuristic extends ScriptHeuristic { @@ -72,7 +70,7 @@ public class ScriptHeuristic extends SignificanceHeuristic { supersetSizeHolder.value = supersetSize; subsetDfHolder.value = subsetFreq; supersetDfHolder.value = supersetFreq; - return ((Number) executableScript.run()).doubleValue(); + return ((Number) executableScript.run()).doubleValue(); } } @@ -94,12 +92,12 @@ public class ScriptHeuristic extends SignificanceHeuristic { @Override public SignificanceHeuristic rewrite(InternalAggregation.ReduceContext context) { - return new ExecutableScriptHeuristic(script, context.scriptService().executable(script, ScriptContext.Standard.AGGS, Collections.emptyMap())); + return new ExecutableScriptHeuristic(script, context.scriptService().executable(script, ScriptContext.Standard.AGGS)); } @Override public SignificanceHeuristic rewrite(SearchContext context) { - return new ExecutableScriptHeuristic(script, context.getQueryShardContext().getExecutableScript(script, ScriptContext.Standard.AGGS, Collections.emptyMap())); + return new ExecutableScriptHeuristic(script, context.getQueryShardContext().getExecutableScript(script, ScriptContext.Standard.AGGS)); } @@ -125,7 +123,7 @@ public class ScriptHeuristic extends SignificanceHeuristic { @Override public XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException { builder.startObject(NAME); - builder.field(ScriptField.SCRIPT.getPreferredName()); + builder.field(Script.SCRIPT_PARSE_FIELD.getPreferredName()); script.toXContent(builder, builderParams); builder.endObject(); return builder; @@ -159,7 +157,7 @@ public class ScriptHeuristic extends SignificanceHeuristic { if (token.equals(XContentParser.Token.FIELD_NAME)) { currentFieldName = parser.currentName(); } else { - if (context.matchField(currentFieldName, ScriptField.SCRIPT)) { + if (context.matchField(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); } else { throw new ElasticsearchParseException("failed to parse [{}] significance heuristic. unknown object [{}]", heuristicName, currentFieldName); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java index f044e94f05..6e48d844c7 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java @@ -191,17 +191,15 @@ public class ScriptedMetricAggregationBuilder extends AbstractAggregationBuilder QueryShardContext queryShardContext = context.searchContext().getQueryShardContext(); Function, ExecutableScript> executableInitScript; if (initScript != null) { - executableInitScript = queryShardContext.getLazyExecutableScript(initScript, ScriptContext.Standard.AGGS, - Collections.emptyMap()); + executableInitScript = queryShardContext.getLazyExecutableScript(initScript, ScriptContext.Standard.AGGS); } else { executableInitScript = (p) -> null;; } Function, SearchScript> searchMapScript = queryShardContext.getLazySearchScript(mapScript, - ScriptContext.Standard.AGGS, Collections.emptyMap()); + ScriptContext.Standard.AGGS); Function, ExecutableScript> executableCombineScript; if (combineScript != null) { - executableCombineScript = queryShardContext.getLazyExecutableScript(combineScript, ScriptContext.Standard.AGGS, - Collections.emptyMap()); + executableCombineScript = queryShardContext.getLazyExecutableScript(combineScript, ScriptContext.Standard.AGGS); } else { executableCombineScript = (p) -> null; } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java index d6150fa874..7cb74b9ecb 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java @@ -91,7 +91,7 @@ public class ScriptedMetricAggregatorFactory extends AggregatorFactory map = parser.map(); @@ -223,7 +222,7 @@ public class BucketScriptPipelineAggregationBuilder extends AbstractPipelineAggr } if (script == null) { - throw new ParsingException(parser.getTokenLocation(), "Missing required field [" + ScriptField.SCRIPT.getPreferredName() + throw new ParsingException(parser.getTokenLocation(), "Missing required field [" + Script.SCRIPT_PARSE_FIELD.getPreferredName() + "] for series_arithmetic aggregation [" + reducerName + "]"); } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregationBuilder.java index e3b4237672..877be6ea54 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregationBuilder.java @@ -26,7 +26,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.script.Script; -import org.elasticsearch.script.Script.ScriptField; import org.elasticsearch.search.aggregations.pipeline.AbstractPipelineAggregationBuilder; import org.elasticsearch.search.aggregations.pipeline.BucketHelpers.GapPolicy; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; @@ -119,7 +118,7 @@ public class BucketSelectorPipelineAggregationBuilder extends AbstractPipelineAg @Override protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException { builder.field(BUCKETS_PATH.getPreferredName(), bucketsPathsMap); - builder.field(ScriptField.SCRIPT.getPreferredName(), script); + builder.field(Script.SCRIPT_PARSE_FIELD.getPreferredName(), script); builder.field(GAP_POLICY.getPreferredName(), gapPolicy.getName()); return builder; } @@ -141,7 +140,7 @@ public class BucketSelectorPipelineAggregationBuilder extends AbstractPipelineAg bucketsPathsMap.put("_value", parser.text()); } else if (context.getParseFieldMatcher().match(currentFieldName, GAP_POLICY)) { gapPolicy = GapPolicy.parse(context, parser.text(), parser.getTokenLocation()); - } else if (context.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) { + } else if (context.getParseFieldMatcher().match(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); } else { throw new ParsingException(parser.getTokenLocation(), @@ -163,7 +162,7 @@ public class BucketSelectorPipelineAggregationBuilder extends AbstractPipelineAg "Unknown key for a " + token + " in [" + reducerName + "]: [" + currentFieldName + "]."); } } else if (token == XContentParser.Token.START_OBJECT) { - if (context.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) { + if (context.getParseFieldMatcher().match(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); } else if (context.getParseFieldMatcher().match(currentFieldName, BUCKETS_PATH)) { Map map = parser.map(); @@ -186,7 +185,7 @@ public class BucketSelectorPipelineAggregationBuilder extends AbstractPipelineAg } if (script == null) { - throw new ParsingException(parser.getTokenLocation(), "Missing required field [" + ScriptField.SCRIPT.getPreferredName() + throw new ParsingException(parser.getTokenLocation(), "Missing required field [" + Script.SCRIPT_PARSE_FIELD.getPreferredName() + "] for bucket_selector aggregation [" + reducerName + "]"); } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/support/AbstractValuesSourceParser.java b/core/src/main/java/org/elasticsearch/search/aggregations/support/AbstractValuesSourceParser.java index e2fd8451ae..7e8c5c1b27 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/support/AbstractValuesSourceParser.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/support/AbstractValuesSourceParser.java @@ -24,7 +24,6 @@ import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.script.Script; -import org.elasticsearch.script.Script.ScriptField; import org.elasticsearch.search.aggregations.Aggregator; import org.joda.time.DateTimeZone; @@ -133,7 +132,7 @@ public abstract class AbstractValuesSourceParser "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "]."); } } else if (scriptable && token == XContentParser.Token.START_OBJECT) { - if (context.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) { + if (context.getParseFieldMatcher().match(currentFieldName, Script.SCRIPT_PARSE_FIELD)) { script = Script.parse(parser, context.getParseFieldMatcher(), context.getDefaultScriptLanguage()); } else if (!token(aggregationName, currentFieldName, token, parserContext, otherOptions)) { throw new ParsingException(parser.getTokenLocation(), diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSourceAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSourceAggregationBuilder.java index f539a2a3b7..1c06296f38 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSourceAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSourceAggregationBuilder.java @@ -376,7 +376,7 @@ public abstract class ValuesSourceAggregationBuilder { a -> new ScriptSortBuilder((Script) a[0], (ScriptSortType) a[1])); static { - PARSER.declareField(constructorArg(), Script::parse, ScriptField.SCRIPT, ValueType.OBJECT_OR_STRING); + PARSER.declareField(constructorArg(), Script::parse, Script.SCRIPT_PARSE_FIELD, ValueType.OBJECT_OR_STRING); PARSER.declareField(constructorArg(), p -> ScriptSortType.fromString(p.text()), TYPE_FIELD, ValueType.STRING); PARSER.declareString((b, v) -> b.order(SortOrder.fromString(v)), ORDER_FIELD); PARSER.declareString((b, v) -> b.sortMode(SortMode.fromString(v)), SORTMODE_FIELD); @@ -242,7 +240,7 @@ public class ScriptSortBuilder extends SortBuilder { @Override public SortFieldAndFormat build(QueryShardContext context) throws IOException { - final SearchScript searchScript = context.getSearchScript(script, ScriptContext.Standard.SEARCH, Collections.emptyMap()); + final SearchScript searchScript = context.getSearchScript(script, ScriptContext.Standard.SEARCH); MultiValueMode valueMode = null; if (sortMode != null) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java index 445924680b..969b1c24d5 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java @@ -393,7 +393,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder, ExecutableScript> compiledScript = context.getLazyExecutableScript(this.collateQuery, - ScriptContext.Standard.SEARCH, Collections.emptyMap()); + ScriptContext.Standard.SEARCH); suggestionContext.setCollateQueryScript(compiledScript); if (this.collateParams != null) { suggestionContext.setCollateScriptParams(this.collateParams); -- cgit v1.2.3