diff options
author | Ryan Ernst <ryan@iernst.net> | 2017-05-24 14:29:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-24 14:29:02 -0700 |
commit | 1daacd97b07b601a8a27a8bf64aaf132d2a1931d (patch) | |
tree | 5321e4d094f9c435f23947134fa71a523e5c65ea | |
parent | 0ddd21942315092d76b43786b45c5ebb015849a5 (diff) |
Scripting: Add instance and compiled classes to script contexts (#24868)
This commit modifies the compile method of ScriptService to be context
aware. The ScriptContext is now a generic class which contains both the
instance type and compiled type for a script. Instance type may be
stateful (for example, pre loading field information for the index a
script will execute on, like in expressions), while the compiled type is
stateless and used to construct instance type instances. This change is
only a first step to cutover ScriptService to the new paradigm. It only
converts callers to the script service, and has a small shim to wrap
compilation from the script engines to support the current two fixed
instance types, SearchScript and ExecutableScript.
42 files changed, 227 insertions, 365 deletions
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 c88b604e8c..c62c391ac7 100644 --- a/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java +++ b/core/src/main/java/org/elasticsearch/action/update/UpdateHelper.java @@ -44,7 +44,6 @@ import org.elasticsearch.index.mapper.ParentFieldMapper; import org.elasticsearch.index.mapper.RoutingFieldMapper; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -301,8 +300,8 @@ public class UpdateHelper extends AbstractComponent { private Map<String, Object> executeScript(Script script, Map<String, Object> ctx) { try { if (scriptService != null) { - CompiledScript compiledScript = scriptService.compile(script, ScriptContext.UPDATE); - ExecutableScript executableScript = scriptService.executable(compiledScript, script.getParams()); + ExecutableScript.Compiled compiledScript = scriptService.compile(script, ScriptContext.UPDATE); + ExecutableScript executableScript = compiledScript.newInstance(script.getParams()); executableScript.setNextVar(ContextFields.CTX, ctx); executableScript.run(); } 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 37473710e2..dcad54d52c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java @@ -20,13 +20,10 @@ package org.elasticsearch.index.query; import org.apache.lucene.index.IndexReader; import org.elasticsearch.client.Client; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.mapper.MapperService; -import org.elasticsearch.script.CompiledScript; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; @@ -106,7 +103,7 @@ public class QueryRewriteContext { } public String getTemplateBytes(Script template) { - CompiledTemplate compiledTemplate = scriptService.compileTemplate(template, ScriptContext.SEARCH); + CompiledTemplate compiledTemplate = scriptService.compileTemplate(template, ScriptContext.EXECUTABLE); return compiledTemplate.run(template.getParams()); } } 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 31b2a71846..c4093be5dd 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -32,7 +32,6 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.index.Index; @@ -50,7 +49,6 @@ import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.mapper.TextFieldMapper; import org.elasticsearch.index.query.support.NestedScope; import org.elasticsearch.index.similarity.SimilarityService; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -331,39 +329,43 @@ 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) { + public final SearchScript getSearchScript(Script script, ScriptContext<SearchScript, SearchScript.Compiled> context) { failIfFrozen(); - CompiledScript compile = scriptService.compile(script, context); - return scriptService.search(lookup(), compile, script.getParams()); + SearchScript.Compiled compiled = scriptService.compile(script, context); + return compiled.newInstance(script.getParams(), lookup()); } /** * Returns a lazily created {@link SearchScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public final Function<Map<String, Object>, SearchScript> getLazySearchScript(Script script, ScriptContext context) { + public final Function<Map<String, Object>, SearchScript> getLazySearchScript( + Script script, ScriptContext<SearchScript, SearchScript.Compiled> context) { + // TODO: this "lazy" binding can be removed once scripted metric aggs have their own contexts, which take _agg/_aggs as a parameter failIfFrozen(); - CompiledScript compile = scriptService.compile(script, context); - return (p) -> scriptService.search(lookup(), compile, p); + SearchScript.Compiled compiled = scriptService.compile(script, context); + return (p) -> compiled.newInstance(p, lookup()); } /** * Compiles (or retrieves from cache) and binds the parameters to the * provided script */ - public final ExecutableScript getExecutableScript(Script script, ScriptContext context) { + public final ExecutableScript getExecutableScript(Script script, ScriptContext<ExecutableScript, ExecutableScript.Compiled> context) { failIfFrozen(); - CompiledScript compiledScript = scriptService.compile(script, context); - return scriptService.executable(compiledScript, script.getParams()); + ExecutableScript.Compiled compiled = scriptService.compile(script, context); + return compiled.newInstance(script.getParams()); } /** * Returns a lazily created {@link ExecutableScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public final Function<Map<String, Object>, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context) { + public final Function<Map<String, Object>, ExecutableScript> getLazyExecutableScript( + Script script, ScriptContext<ExecutableScript, ExecutableScript.Compiled> context) { + // TODO: this "lazy" binding can be removed once scripted metric aggs have their own contexts, which take _agg/_aggs as a parameter failIfFrozen(); - CompiledScript executable = scriptService.compile(script, context); - return (p) -> scriptService.executable(executable, p); + ExecutableScript.Compiled compiled = scriptService.compile(script, context); + return compiled::newInstance; } /** diff --git a/core/src/main/java/org/elasticsearch/script/CompiledScript.java b/core/src/main/java/org/elasticsearch/script/CompiledScript.java deleted file mode 100644 index 818971f0f8..0000000000 --- a/core/src/main/java/org/elasticsearch/script/CompiledScript.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.script; - -/** - * CompiledScript holds all the parameters necessary to execute a previously compiled script. - */ -public class CompiledScript { - - private final ScriptType type; - private final String name; - private final String lang; - private final Object compiled; - - /** - * Constructor for CompiledScript. - * @param type The type of script to be executed. - * @param name The name of the script to be executed. - * @param lang The language of the script to be executed. - * @param compiled The compiled script Object that is executable. - */ - public CompiledScript(ScriptType type, String name, String lang, Object compiled) { - this.type = type; - this.name = name; - this.lang = lang; - this.compiled = compiled; - } - - /** - * Method to get the type of language. - * @return The type of language the script was compiled in. - */ - public ScriptType type() { - return type; - } - - /** - * Method to get the name of the script. - * @return The name of the script to be executed. - */ - public String name() { - return name; - } - - /** - * Method to get the language. - * @return The language of the script to be executed. - */ - public String lang() { - return lang; - } - - /** - * Method to get the compiled script object. - * @return The compiled script Object that is executable. - */ - public Object compiled() { - return compiled; - } - - /** - * @return A string composed of type, lang, and name to describe the CompiledScript. - */ - @Override - public String toString() { - return type + " script [" + name + "] using lang [" + lang + "]"; - } -} diff --git a/core/src/main/java/org/elasticsearch/script/ExecutableScript.java b/core/src/main/java/org/elasticsearch/script/ExecutableScript.java index e3f8eb4744..0d025c020e 100644 --- a/core/src/main/java/org/elasticsearch/script/ExecutableScript.java +++ b/core/src/main/java/org/elasticsearch/script/ExecutableScript.java @@ -19,6 +19,8 @@ package org.elasticsearch.script; +import java.util.Map; + /** * An executable script, can't be used concurrently. */ @@ -38,4 +40,8 @@ public interface ExecutableScript { * Executes the script. */ Object run(); + + interface Compiled { + ExecutableScript newInstance(Map<String, Object> params); + } } diff --git a/core/src/main/java/org/elasticsearch/script/ScriptContext.java b/core/src/main/java/org/elasticsearch/script/ScriptContext.java index cd3bff3379..03bcb376e5 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptContext.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptContext.java @@ -24,30 +24,65 @@ import java.util.HashMap; import java.util.Map; /** - * A holder for information about a context in which a script is compiled and run. + * The information necessary to compile and run a script. + * + * A {@link ScriptContext} contains the information related to a single use case and the interfaces + * and methods necessary for a {@link ScriptEngine} to implement. + * <p> + * There are two related classes which must be supplied to construct a {@link ScriptContext}. + * <p> + * The <i>InstanceType</i> is a class, possibly stateful, that is an instance of a script. Instances of + * the <i>InstanceType</i> may be executed multiple times by a caller with different arguments. This + * class must have an abstract method named <i>execute</i> which {@link ScriptEngine} implementations + * will define. + * <p> + * The <i>CompiledType</i> is a factory class for constructing instances of a script. The + * {@link ScriptService} returns an instance of <i>CompiledType</i> when compiling a script. This class + * must be stateless so it is cacheable by the {@link ScriptService}. It must have an abstract method + * named <i>newInstance</i> which returns <i>InstanceType</i> which {@link ScriptEngine} implementations + * will define. */ -public final class ScriptContext { +public final class ScriptContext<InstanceType, CompiledType> { - public static final ScriptContext AGGS = new ScriptContext("aggs"); - public static final ScriptContext SEARCH = new ScriptContext("search"); - public static final ScriptContext UPDATE = new ScriptContext("update"); - public static final ScriptContext INGEST = new ScriptContext("ingest"); + public static final ScriptContext<SearchScript, SearchScript.Compiled> AGGS = + new ScriptContext<>("aggs", SearchScript.class, SearchScript.Compiled.class); + public static final ScriptContext<SearchScript, SearchScript.Compiled> SEARCH = + new ScriptContext<>("search", SearchScript.class, SearchScript.Compiled.class); + // TODO: remove this once each agg calling scripts has its own context + public static final ScriptContext<ExecutableScript, ExecutableScript.Compiled> AGGS_EXECUTABLE = + new ScriptContext<>("aggs_executable", ExecutableScript.class, ExecutableScript.Compiled.class); + public static final ScriptContext<ExecutableScript, ExecutableScript.Compiled> UPDATE = + new ScriptContext<>("update", ExecutableScript.class, ExecutableScript.Compiled.class); + public static final ScriptContext<ExecutableScript, ExecutableScript.Compiled> INGEST = + new ScriptContext<>("ingest", ExecutableScript.class, ExecutableScript.Compiled.class); + public static final ScriptContext<ExecutableScript, ExecutableScript.Compiled> EXECUTABLE = + new ScriptContext<>("executable", ExecutableScript.class, ExecutableScript.Compiled.class); - public static final Map<String, ScriptContext> BUILTINS; + public static final Map<String, ScriptContext<?, ?>> BUILTINS; static { - Map<String, ScriptContext> builtins = new HashMap<>(); + Map<String, ScriptContext<?, ?>> builtins = new HashMap<>(); builtins.put(AGGS.name, AGGS); builtins.put(SEARCH.name, SEARCH); + builtins.put(AGGS_EXECUTABLE.name, AGGS_EXECUTABLE); builtins.put(UPDATE.name, UPDATE); builtins.put(INGEST.name, INGEST); + builtins.put(EXECUTABLE.name, EXECUTABLE); BUILTINS = Collections.unmodifiableMap(builtins); } /** A unique identifier for this context. */ public final String name; - // pkg private ctor, only created by script module - public ScriptContext(String name) { + /** A class that is an instance of a script. */ + public final Class<InstanceType> instanceClazz; + + /** A factory class for constructing instances of a script. */ + public final Class<CompiledType> compiledClazz; + + /** Construct a context with the related instance and compiled classes. */ + public ScriptContext(String name, Class<InstanceType> instanceClazz, Class<CompiledType> compiledClazz) { this.name = name; + this.instanceClazz = instanceClazz; + this.compiledClazz = compiledClazz; } } diff --git a/core/src/main/java/org/elasticsearch/script/ScriptEngine.java b/core/src/main/java/org/elasticsearch/script/ScriptEngine.java index 2256ecbb26..396ed73d90 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptEngine.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptEngine.java @@ -45,9 +45,9 @@ public interface ScriptEngine extends Closeable { */ Object compile(String name, String code, Map<String, String> params); - ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars); - - SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars); + ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars); + + SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars); @Override default void close() throws IOException {} diff --git a/core/src/main/java/org/elasticsearch/script/ScriptModule.java b/core/src/main/java/org/elasticsearch/script/ScriptModule.java index b29a199c3a..8fd17d4e1b 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptModule.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptModule.java @@ -36,7 +36,7 @@ public class ScriptModule { public ScriptModule(Settings settings, List<ScriptPlugin> scriptPlugins) { Map<String, ScriptEngine> engines = new HashMap<>(); - Map<String, ScriptContext> contexts = new HashMap<>(ScriptContext.BUILTINS); + Map<String, ScriptContext<?, ?>> contexts = new HashMap<>(ScriptContext.BUILTINS); for (ScriptPlugin plugin : scriptPlugins) { for (ScriptContext context : plugin.getContexts()) { ScriptContext oldContext = contexts.put(context.name, context); diff --git a/core/src/main/java/org/elasticsearch/script/ScriptService.java b/core/src/main/java/org/elasticsearch/script/ScriptService.java index e5892ef1dc..3ce1c89d04 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptService.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptService.java @@ -45,7 +45,6 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.template.CompiledTemplate; import java.io.Closeable; @@ -82,9 +81,9 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust private final Set<String> contextsAllowed; private final Map<String, ScriptEngine> engines; - private final Map<String, ScriptContext> contexts; + private final Map<String, ScriptContext<?,?>> contexts; - private final Cache<CacheKey, CompiledScript> cache; + private final Cache<CacheKey, Object> cache; private final ScriptMetrics scriptMetrics = new ScriptMetrics(); @@ -95,7 +94,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust private double scriptsPerMinCounter; private double compilesAllowedPerNano; - public ScriptService(Settings settings, Map<String, ScriptEngine> engines, Map<String, ScriptContext> contexts) { + public ScriptService(Settings settings, Map<String, ScriptEngine> engines, Map<String, ScriptContext<?,?>> contexts) { super(settings); Objects.requireNonNull(settings); @@ -176,7 +175,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust int cacheMaxSize = SCRIPT_CACHE_SIZE_SETTING.get(settings); - CacheBuilder<CacheKey, CompiledScript> cacheBuilder = CacheBuilder.builder(); + CacheBuilder<CacheKey, Object> cacheBuilder = CacheBuilder.builder(); if (cacheMaxSize >= 0) { cacheBuilder.setMaximumWeight(cacheMaxSize); } @@ -218,9 +217,11 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust } /** - * Checks if a script can be executed and compiles it if needed, or returns the previously compiled and cached script. + * Compiles a script using the given context. + * + * @return a compiled script which may be used to construct instances of a script for the given context */ - public CompiledScript compile(Script script, ScriptContext context) { + public <InstanceType, CompiledType> CompiledType compile(Script script, ScriptContext<InstanceType, CompiledType> context) { Objects.requireNonNull(script); Objects.requireNonNull(context); @@ -287,11 +288,11 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust logger.trace("compiling lang: [{}] type: [{}] script: {}", lang, type, idOrCode); } - CacheKey cacheKey = new CacheKey(lang, idOrCode, options); - CompiledScript compiledScript = cache.get(cacheKey); + CacheKey cacheKey = new CacheKey(lang, idOrCode, context.name, options); + Object compiledScript = cache.get(cacheKey); if (compiledScript != null) { - return compiledScript; + return context.compiledClazz.cast(compiledScript); } // Synchronize so we don't compile scripts many times during multiple shards all compiling a script @@ -311,7 +312,14 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust } // Check whether too many compilations have happened checkCompilationLimit(); - compiledScript = new CompiledScript(type, id, lang, scriptEngine.compile(id, idOrCode, options)); + Object engineCompiled = scriptEngine.compile(id, idOrCode, options); + if (context.instanceClazz == ExecutableScript.class) { + compiledScript = (ExecutableScript.Compiled) params -> scriptEngine.executable(engineCompiled, params); + } else if (context.instanceClazz == SearchScript.class) { + compiledScript = (SearchScript.Compiled) (params, lookup) -> scriptEngine.search(engineCompiled, lookup, params); + } else { + throw new IllegalArgumentException("Script context [" + context.name + "] not supported"); + } } catch (ScriptException good) { // TODO: remove this try-catch completely, when all script engines have good exceptions! throw good; // its already good @@ -325,14 +333,14 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust cache.put(cacheKey, compiledScript); } - return compiledScript; + return context.compiledClazz.cast(compiledScript); } } /** Compiles a template. Note this will be moved to a separate TemplateService in the future. */ - public CompiledTemplate compileTemplate(Script script, ScriptContext scriptContext) { - CompiledScript compiledScript = compile(script, scriptContext); - return params -> (String)executable(compiledScript, params).run(); + public CompiledTemplate compileTemplate(Script script, ScriptContext<ExecutableScript, ExecutableScript.Compiled> scriptContext) { + ExecutableScript.Compiled compiledScript = compile(script, scriptContext); + return params -> (String)compiledScript.newInstance(params).run(); } /** @@ -498,21 +506,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust } } - /** - * Executes a previously compiled script provided as an argument - */ - public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) { - return getEngine(compiledScript.lang()).executable(compiledScript, params); - } - - /** - * Binds provided parameters to a compiled script returning a - * {@link SearchScript} ready for execution - */ - public SearchScript search(SearchLookup lookup, CompiledScript compiledScript, Map<String, Object> params) { - return getEngine(compiledScript.lang()).search(compiledScript, lookup, params); - } - public ScriptStats stats() { return scriptMetrics.stats(); } @@ -527,9 +520,9 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust * {@code ScriptEngine}'s {@code scriptRemoved} method when the * script has been removed from the cache */ - private class ScriptCacheRemovalListener implements RemovalListener<CacheKey, CompiledScript> { + private class ScriptCacheRemovalListener implements RemovalListener<CacheKey, Object> { @Override - public void onRemoval(RemovalNotification<CacheKey, CompiledScript> notification) { + public void onRemoval(RemovalNotification<CacheKey, Object> notification) { if (logger.isDebugEnabled()) { logger.debug("removed {} from cache, reason: {}", notification.getValue(), notification.getRemovalReason()); } @@ -540,11 +533,13 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust private static final class CacheKey { final String lang; final String idOrCode; + final String context; final Map<String, String> options; - private CacheKey(String lang, String idOrCode, Map<String, String> options) { + private CacheKey(String lang, String idOrCode, String context, Map<String, String> options) { this.lang = lang; this.idOrCode = idOrCode; + this.context = context; this.options = options; } @@ -552,21 +547,16 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - - CacheKey cacheKey = (CacheKey)o; - - if (lang != null ? !lang.equals(cacheKey.lang) : cacheKey.lang != null) return false; - if (!idOrCode.equals(cacheKey.idOrCode)) return false; - return options != null ? options.equals(cacheKey.options) : cacheKey.options == null; - + CacheKey cacheKey = (CacheKey) o; + return Objects.equals(lang, cacheKey.lang) && + Objects.equals(idOrCode, cacheKey.idOrCode) && + Objects.equals(context, cacheKey.context) && + Objects.equals(options, cacheKey.options); } @Override public int hashCode() { - int result = lang != null ? lang.hashCode() : 0; - result = 31 * result + idOrCode.hashCode(); - result = 31 * result + (options != null ? options.hashCode() : 0); - return result; + return Objects.hash(lang, idOrCode, context, options); } } } diff --git a/core/src/main/java/org/elasticsearch/script/SearchScript.java b/core/src/main/java/org/elasticsearch/script/SearchScript.java index 5d5f218763..5758209a48 100644 --- a/core/src/main/java/org/elasticsearch/script/SearchScript.java +++ b/core/src/main/java/org/elasticsearch/script/SearchScript.java @@ -19,8 +19,10 @@ package org.elasticsearch.script; import org.apache.lucene.index.LeafReaderContext; +import org.elasticsearch.search.lookup.SearchLookup; import java.io.IOException; +import java.util.Map; /** * A search script. @@ -36,4 +38,7 @@ public interface SearchScript { */ boolean needsScores(); + interface Compiled { + SearchScript newInstance(Map<String, Object> params, SearchLookup lookup); + } }
\ No newline at end of file diff --git a/core/src/main/java/org/elasticsearch/search/SearchService.java b/core/src/main/java/org/elasticsearch/search/SearchService.java index a5ad038fd5..7f98a876e9 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchService.java +++ b/core/src/main/java/org/elasticsearch/search/SearchService.java @@ -48,7 +48,6 @@ import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.SearchOperationListener; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.SearchScript; @@ -686,8 +685,8 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv } if (source.scriptFields() != null) { for (org.elasticsearch.search.builder.SearchSourceBuilder.ScriptField field : source.scriptFields()) { - CompiledScript compile = scriptService.compile(field.script(), ScriptContext.SEARCH); - SearchScript searchScript = scriptService.search(context.lookup(), compile, field.script().getParams()); + SearchScript.Compiled compiled = scriptService.compile(field.script(), ScriptContext.SEARCH); + SearchScript searchScript = compiled.newInstance(field.script().getParams(), context.lookup()); 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 b3df54247b..70ccf53200 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 @@ -28,7 +28,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardException; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -93,13 +92,14 @@ public class ScriptHeuristic extends SignificanceHeuristic { @Override public SignificanceHeuristic rewrite(InternalAggregation.ReduceContext context) { - CompiledScript compiledScript = context.scriptService().compile(script, ScriptContext.AGGS); - return new ExecutableScriptHeuristic(script, context.scriptService().executable(compiledScript, script.getParams())); + ExecutableScript.Compiled compiled = context.scriptService().compile(script, ScriptContext.AGGS_EXECUTABLE); + return new ExecutableScriptHeuristic(script, compiled.newInstance(script.getParams())); } @Override public SignificanceHeuristic rewrite(SearchContext context) { - return new ExecutableScriptHeuristic(script, context.getQueryShardContext().getExecutableScript(script, ScriptContext.AGGS)); + return new ExecutableScriptHeuristic(script, + context.getQueryShardContext().getExecutableScript(script, ScriptContext.AGGS_EXECUTABLE)); } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java index 2bedd16ebf..b0a4836a69 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java @@ -22,7 +22,6 @@ package org.elasticsearch.search.aggregations.metrics.scripted; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -96,9 +95,9 @@ public class InternalScriptedMetric extends InternalAggregation implements Scrip if (firstAggregation.reduceScript.getParams() != null) { vars.putAll(firstAggregation.reduceScript.getParams()); } - CompiledScript compiledScript = reduceContext.scriptService().compile( - firstAggregation.reduceScript, ScriptContext.AGGS); - ExecutableScript script = reduceContext.scriptService().executable(compiledScript, vars); + ExecutableScript.Compiled compiled = reduceContext.scriptService().compile( + firstAggregation.reduceScript, ScriptContext.AGGS_EXECUTABLE); + ExecutableScript script = compiled.newInstance(vars); aggregation = Collections.singletonList(script.run()); } else if (reduceContext.isFinalReduce()) { aggregation = Collections.singletonList(aggregationObjects); 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 6d8c297eeb..6865d6a211 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 @@ -186,15 +186,14 @@ public class ScriptedMetricAggregationBuilder extends AbstractAggregationBuilder QueryShardContext queryShardContext = context.getQueryShardContext(); Function<Map<String, Object>, ExecutableScript> executableInitScript; if (initScript != null) { - executableInitScript = queryShardContext.getLazyExecutableScript(initScript, ScriptContext.AGGS); + executableInitScript = queryShardContext.getLazyExecutableScript(initScript, ScriptContext.AGGS_EXECUTABLE); } else { executableInitScript = (p) -> null; } - Function<Map<String, Object>, SearchScript> searchMapScript = queryShardContext.getLazySearchScript(mapScript, - ScriptContext.AGGS); + Function<Map<String, Object>, SearchScript> searchMapScript = queryShardContext.getLazySearchScript(mapScript, ScriptContext.AGGS); Function<Map<String, Object>, ExecutableScript> executableCombineScript; if (combineScript != null) { - executableCombineScript = queryShardContext.getLazyExecutableScript(combineScript, ScriptContext.AGGS); + executableCombineScript = queryShardContext.getLazyExecutableScript(combineScript, ScriptContext.AGGS_EXECUTABLE); } else { executableCombineScript = (p) -> null; } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java index 46f4fbb237..e81bae2044 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java @@ -21,7 +21,6 @@ package org.elasticsearch.search.aggregations.pipeline.bucketscript; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -91,7 +90,7 @@ public class BucketScriptPipelineAggregator extends PipelineAggregator { (InternalMultiBucketAggregation<InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket>) aggregation; List<? extends InternalMultiBucketAggregation.InternalBucket> buckets = originalAgg.getBuckets(); - CompiledScript compiledScript = reduceContext.scriptService().compile(script, ScriptContext.AGGS); + ExecutableScript.Compiled compiledScript = reduceContext.scriptService().compile(script, ScriptContext.AGGS_EXECUTABLE); List<InternalMultiBucketAggregation.InternalBucket> newBuckets = new ArrayList<>(); for (InternalMultiBucketAggregation.InternalBucket bucket : buckets) { Map<String, Object> vars = new HashMap<>(); @@ -112,7 +111,7 @@ public class BucketScriptPipelineAggregator extends PipelineAggregator { if (skipBucket) { newBuckets.add(bucket); } else { - ExecutableScript executableScript = reduceContext.scriptService().executable(compiledScript, vars); + ExecutableScript executableScript = compiledScript.newInstance(vars); Object returned = executableScript.run(); if (returned == null) { newBuckets.add(bucket); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregator.java b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregator.java index f5bc5cc4ad..95d371c474 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregator.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketselector/BucketSelectorPipelineAggregator.java @@ -22,7 +22,6 @@ package org.elasticsearch.search.aggregations.pipeline.bucketselector; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -84,7 +83,7 @@ public class BucketSelectorPipelineAggregator extends PipelineAggregator { (InternalMultiBucketAggregation<InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket>) aggregation; List<? extends InternalMultiBucketAggregation.InternalBucket> buckets = originalAgg.getBuckets(); - CompiledScript compiledScript = reduceContext.scriptService().compile(script, ScriptContext.AGGS); + ExecutableScript.Compiled compiledScript = reduceContext.scriptService().compile(script, ScriptContext.AGGS_EXECUTABLE); List<InternalMultiBucketAggregation.InternalBucket> newBuckets = new ArrayList<>(); for (InternalMultiBucketAggregation.InternalBucket bucket : buckets) { Map<String, Object> vars = new HashMap<>(); @@ -97,7 +96,8 @@ public class BucketSelectorPipelineAggregator extends PipelineAggregator { Double value = resolveBucketValue(originalAgg, bucket, bucketsPath, gapPolicy); vars.put(varName, value); } - ExecutableScript executableScript = reduceContext.scriptService().executable(compiledScript, vars); + // TODO: can we use one instance of the script for all buckets? it should be stateless? + ExecutableScript executableScript = compiledScript.newInstance(vars); Object scriptReturnValue = executableScript.run(); final boolean keepBucket; // TODO: WTF!!!!! 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 f5a6eca35b..1319679f1a 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 @@ -631,7 +631,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB if (this.collateQuery != null) { Function<Map<String, Object>, ExecutableScript> compiledScript = context.getLazyExecutableScript(this.collateQuery, - ScriptContext.SEARCH); + ScriptContext.EXECUTABLE); suggestionContext.setCollateQueryScript(compiledScript); if (this.collateParams != null) { suggestionContext.setCollateScriptParams(this.collateParams); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java index 99e2e18496..31dcc22bec 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java @@ -23,7 +23,6 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Terms; import org.apache.lucene.util.BytesRef; import org.elasticsearch.index.query.QueryShardContext; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.search.suggest.DirectSpellcheckerSettings; import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext; diff --git a/core/src/main/java/org/elasticsearch/template/CompiledTemplate.java b/core/src/main/java/org/elasticsearch/template/CompiledTemplate.java index 380c36a590..d03993583c 100644 --- a/core/src/main/java/org/elasticsearch/template/CompiledTemplate.java +++ b/core/src/main/java/org/elasticsearch/template/CompiledTemplate.java @@ -21,10 +21,6 @@ package org.elasticsearch.template; import java.util.Map; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.script.CompiledScript; -import org.elasticsearch.script.ScriptType; - /** * A template that may be executed. */ diff --git a/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java b/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java index cdd939cf60..79241781b0 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java @@ -51,7 +51,7 @@ public class ScriptServiceTests extends ESTestCase { private ScriptEngine scriptEngine; private Map<String, ScriptEngine> engines; - private Map<String, ScriptContext> contexts; + private Map<String, ScriptContext<?,?>> contexts; private ScriptService scriptService; private Settings baseSettings; @@ -123,11 +123,10 @@ public class ScriptServiceTests extends ESTestCase { public void testInlineScriptCompiledOnceCache() throws IOException { buildScriptService(Settings.EMPTY); - CompiledScript compiledScript1 = scriptService.compile(new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()), - randomFrom(contexts.values())); - CompiledScript compiledScript2 = scriptService.compile(new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()), - randomFrom(contexts.values())); - assertThat(compiledScript1.compiled(), sameInstance(compiledScript2.compiled())); + Script script = new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()); + SearchScript.Compiled compiledScript1 = scriptService.compile(script, ScriptContext.SEARCH); + SearchScript.Compiled compiledScript2 = scriptService.compile(script, ScriptContext.SEARCH); + assertThat(compiledScript1, sameInstance(compiledScript2)); } public void testAllowAllScriptTypeSettings() throws IOException { @@ -199,22 +198,6 @@ public class ScriptServiceTests extends ESTestCase { assertEquals(1L, scriptService.stats().getCompilations()); } - public void testExecutableCountedInCompilationStats() throws IOException { - buildScriptService(Settings.EMPTY); - Script script = new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()); - CompiledScript compiledScript = scriptService.compile(script, randomFrom(contexts.values())); - scriptService.executable(compiledScript, script.getParams()); - assertEquals(1L, scriptService.stats().getCompilations()); - } - - public void testSearchCountedInCompilationStats() throws IOException { - buildScriptService(Settings.EMPTY); - Script script = new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()); - CompiledScript compile = scriptService.compile(script, randomFrom(contexts.values())); - scriptService.search(null, compile, script.getParams()); - assertEquals(1L, scriptService.stats().getCompilations()); - } - public void testMultipleCompilationsCountedInCompilationStats() throws IOException { buildScriptService(Settings.EMPTY); int numberOfCompilations = randomIntBetween(1, 20); @@ -230,8 +213,9 @@ public class ScriptServiceTests extends ESTestCase { builder.put(ScriptService.SCRIPT_CACHE_SIZE_SETTING.getKey(), 1); buildScriptService(builder.build()); Script script = new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()); - scriptService.compile(script, randomFrom(contexts.values())); - scriptService.compile(script, randomFrom(contexts.values())); + ScriptContext<?, ?> context = randomFrom(contexts.values()); + scriptService.compile(script, context); + scriptService.compile(script, context); assertEquals(1L, scriptService.stats().getCompilations()); } @@ -251,14 +235,6 @@ public class ScriptServiceTests extends ESTestCase { assertEquals(1L, scriptService.stats().getCacheEvictions()); } - public void testDefaultLanguage() throws IOException { - Settings.Builder builder = Settings.builder(); - buildScriptService(builder.build()); - CompiledScript script = scriptService.compile( - new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "1+1", Collections.emptyMap()), randomFrom(contexts.values())); - assertEquals(script.lang(), Script.DEFAULT_SCRIPT_LANG); - } - public void testStoreScript() throws Exception { BytesReference script = XContentFactory.jsonBuilder().startObject() .field("script", "abc") diff --git a/core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java b/core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java index 8711e9ef3d..d27a297926 100644 --- a/core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java +++ b/core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java @@ -30,7 +30,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.ScriptPlugin; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ExplainableSearchScript; import org.elasticsearch.script.LeafSearchScript; @@ -84,12 +83,12 @@ public class ExplainableScriptIT extends ESIntegTestCase { } @Override - public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) { + public ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars) { throw new UnsupportedOperationException(); } @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { + public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { return new SearchScript() { @Override public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/SuggestSearchIT.java b/core/src/test/java/org/elasticsearch/search/suggest/SuggestSearchIT.java index b11d6ce07a..1327af8f3e 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/SuggestSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/SuggestSearchIT.java @@ -25,13 +25,11 @@ import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.ScriptPlugin; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.SearchScript; @@ -1032,8 +1030,8 @@ public class SuggestSearchIT extends ESIntegTestCase { } @Override - public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) { - String script = (String) compiledScript.compiled(); + public ExecutableScript executable(Object compiledScript, Map<String, Object> params) { + String script = (String) compiledScript; for (Entry<String, Object> entry : params.entrySet()) { script = script.replace("{{" + entry.getKey() + "}}", String.valueOf(entry.getValue())); } @@ -1052,7 +1050,7 @@ public class SuggestSearchIT extends ESIntegTestCase { } @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) { + public SearchScript search(Object compiledScript, SearchLookup lookup, Map<String, Object> vars) { throw new UnsupportedOperationException("search script not supported"); } } diff --git a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ScriptProcessor.java b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ScriptProcessor.java index a23bdea7a1..2801b24c53 100644 --- a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ScriptProcessor.java +++ b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ScriptProcessor.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.ingest.AbstractProcessor; import org.elasticsearch.ingest.IngestDocument; import org.elasticsearch.ingest.Processor; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -70,8 +69,8 @@ public final class ScriptProcessor extends AbstractProcessor { */ @Override public void execute(IngestDocument document) { - CompiledScript compiledScript = scriptService.compile(script, ScriptContext.INGEST); - ExecutableScript executableScript = scriptService.executable(compiledScript, script.getParams()); + ExecutableScript.Compiled compiledScript = scriptService.compile(script, ScriptContext.INGEST); + ExecutableScript executableScript = compiledScript.newInstance(script.getParams()); executableScript.setNextVar("ctx", document.getSourceAndMetadata()); executableScript.run(); } diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorTests.java index 5356d9c9e0..95fcc13348 100644 --- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorTests.java +++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorTests.java @@ -24,9 +24,9 @@ import java.util.Map; import org.elasticsearch.ingest.IngestDocument; import org.elasticsearch.ingest.RandomDocumentPicks; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; import org.elasticsearch.test.ESTestCase; @@ -46,8 +46,10 @@ public class ScriptProcessorTests extends ESTestCase { ScriptService scriptService = mock(ScriptService.class); Script script = mockScript("_script"); + ExecutableScript.Compiled compiledScript = mock(ExecutableScript.Compiled.class); ExecutableScript executableScript = mock(ExecutableScript.class); - when(scriptService.executable(any(CompiledScript.class), any())).thenReturn(executableScript); + when(scriptService.compile(script, ScriptContext.INGEST)).thenReturn(compiledScript); + when(compiledScript.newInstance(any())).thenReturn(executableScript); Map<String, Object> document = new HashMap<>(); document.put("bytes_in", randomInt()); diff --git a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionExecutableScript.java b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionExecutableScript.java index f5d95f6c88..f9cdae4045 100644 --- a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionExecutableScript.java +++ b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionExecutableScript.java @@ -20,7 +20,6 @@ package org.elasticsearch.script.expression; import org.apache.lucene.expressions.Expression; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.GeneralScriptException; @@ -32,17 +31,16 @@ import java.util.Map; * of an {@link ExecutableScript}. */ public class ExpressionExecutableScript implements ExecutableScript { - public final CompiledScript compiledScript; + public final Expression expression; public final Map<String, ReplaceableConstDoubleValues> functionValuesMap; public final ReplaceableConstDoubleValues[] functionValuesArray; - public ExpressionExecutableScript(CompiledScript compiledScript, Map<String, Object> vars) { - this.compiledScript = compiledScript; - Expression expression = (Expression)this.compiledScript.compiled(); + public ExpressionExecutableScript(Expression expression, Map<String, Object> vars) { + this.expression = expression; int functionValuesLength = expression.variables.length; if (vars.size() != functionValuesLength) { - throw new GeneralScriptException("Error using " + compiledScript + ". " + + throw new GeneralScriptException("Error using " + expression + ". " + "The number of variables in an executable expression script [" + functionValuesLength + "] must match the number of variables in the variable map" + " [" + vars.size() + "]."); @@ -69,12 +67,12 @@ public class ExpressionExecutableScript implements ExecutableScript { double doubleValue = ((Number)value).doubleValue(); functionValuesMap.get(name).setValue(doubleValue); } else { - throw new GeneralScriptException("Error using " + compiledScript + ". " + + throw new GeneralScriptException("Error using " + expression + ". " + "Executable expressions scripts can only process numbers." + " The variable [" + name + "] is not a number."); } } else { - throw new GeneralScriptException("Error using " + compiledScript + ". " + + throw new GeneralScriptException("Error using " + expression + ". " + "The variable [" + name + "] does not exist in the executable expressions script."); } } @@ -82,9 +80,9 @@ public class ExpressionExecutableScript implements ExecutableScript { @Override public Object run() { try { - return ((Expression) compiledScript.compiled()).evaluate(functionValuesArray); + return expression.evaluate(functionValuesArray); } catch (Exception exception) { - throw new GeneralScriptException("Error evaluating " + compiledScript, exception); + throw new GeneralScriptException("Error evaluating " + expression, exception); } } } diff --git a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java index 73d1af32c0..c22e520fb5 100644 --- a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java +++ b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java @@ -37,7 +37,6 @@ import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.ClassPermission; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptException; @@ -104,8 +103,8 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE } @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { - Expression expr = (Expression)compiledScript.compiled(); + public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { + Expression expr = (Expression)compiledScript; MapperService mapper = lookup.doc().mapperService(); // NOTE: if we need to do anything complicated with bindings in the future, we can just extend Bindings, // instead of complicating SimpleBindings (which should stay simple) @@ -227,7 +226,7 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE throw convertToScriptException("link error", expr.sourceText, variable, e); } } - return new ExpressionSearchScript(compiledScript, bindings, specialValue, needsScores); + return new ExpressionSearchScript(expr, bindings, specialValue, needsScores); } /** @@ -249,7 +248,7 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE } @Override - public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> vars) { - return new ExpressionExecutableScript(compiledScript, vars); + public ExecutableScript executable(Object compiledScript, Map<String, Object> vars) { + return new ExpressionExecutableScript((Expression) compiledScript, vars); } } diff --git a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionSearchScript.java b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionSearchScript.java index 11a17d38c5..2e6c010da6 100644 --- a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionSearchScript.java +++ b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionSearchScript.java @@ -26,7 +26,6 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.Scorer; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.GeneralScriptException; import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.SearchScript; @@ -40,7 +39,7 @@ import java.util.Map; */ class ExpressionSearchScript implements SearchScript { - final CompiledScript compiledScript; + final Expression exprScript; final SimpleBindings bindings; final DoubleValuesSource source; final ReplaceableConstDoubleValueSource specialValue; // _value @@ -48,10 +47,10 @@ class ExpressionSearchScript implements SearchScript { Scorer scorer; int docid; - ExpressionSearchScript(CompiledScript c, SimpleBindings b, ReplaceableConstDoubleValueSource v, boolean needsScores) { - compiledScript = c; + ExpressionSearchScript(Expression e, SimpleBindings b, ReplaceableConstDoubleValueSource v, boolean needsScores) { + exprScript = e; bindings = b; - source = ((Expression)compiledScript.compiled()).getDoubleValuesSource(bindings); + source = exprScript.getDoubleValuesSource(bindings); specialValue = v; this.needsScores = needsScores; } @@ -81,7 +80,7 @@ class ExpressionSearchScript implements SearchScript { try { return values.doubleValue(); } catch (Exception exception) { - throw new GeneralScriptException("Error evaluating " + compiledScript, exception); + throw new GeneralScriptException("Error evaluating " + exprScript, exception); } } @@ -100,7 +99,7 @@ class ExpressionSearchScript implements SearchScript { try { values.advanceExact(d); } catch (IOException e) { - throw new IllegalStateException("Can't advance to doc using " + compiledScript, e); + throw new IllegalStateException("Can't advance to doc using " + exprScript, e); } } @@ -121,7 +120,7 @@ class ExpressionSearchScript implements SearchScript { } }); } catch (IOException e) { - throw new IllegalStateException("Can't get values using " + compiledScript, e); + throw new IllegalStateException("Can't get values using " + exprScript, e); } } @@ -137,7 +136,7 @@ class ExpressionSearchScript implements SearchScript { if (value instanceof Number) { specialValue.setValue(((Number)value).doubleValue()); } else { - throw new GeneralScriptException("Cannot use expression with text variable using " + compiledScript); + throw new GeneralScriptException("Cannot use expression with text variable using " + exprScript); } } } diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTests.java index 49b5fa0395..f70238353b 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTests.java @@ -21,9 +21,7 @@ package org.elasticsearch.script.expression; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexService; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ScriptException; -import org.elasticsearch.script.ScriptType; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -45,7 +43,7 @@ public class ExpressionTests extends ESSingleNodeTestCase { private SearchScript compile(String expression) { Object compiled = service.compile(null, expression, Collections.emptyMap()); - return service.search(new CompiledScript(ScriptType.INLINE, "randomName", "expression", compiled), lookup, Collections.<String, Object>emptyMap()); + return service.search(compiled, lookup, Collections.emptyMap()); } public void testNeedsScores() { diff --git a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java index 59f691e889..d8d09ffba7 100644 --- a/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java +++ b/modules/lang-expression/src/test/java/org/elasticsearch/script/expression/MoreExpressionTests.java @@ -33,7 +33,6 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.GeneralScriptException; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptType; @@ -514,9 +513,8 @@ public class MoreExpressionTests extends ESIntegTestCase { vars.put("xyz", -1); Expression expr = JavascriptCompiler.compile("a+b+xyz"); - CompiledScript compiledScript = new CompiledScript(ScriptType.INLINE, "", "expression", expr); - ExpressionExecutableScript ees = new ExpressionExecutableScript(compiledScript, vars); + ExpressionExecutableScript ees = new ExpressionExecutableScript(expr, vars); assertEquals((Double) ees.run(), 4.5, 0.001); ees.setNextVar("b", -2.5); @@ -532,7 +530,7 @@ public class MoreExpressionTests extends ESIntegTestCase { try { vars = new HashMap<>(); vars.put("a", 1); - ees = new ExpressionExecutableScript(compiledScript, vars); + ees = new ExpressionExecutableScript(expr, vars); ees.run(); fail("An incorrect number of variables were allowed to be used in an expression."); } catch (GeneralScriptException se) { @@ -545,7 +543,7 @@ public class MoreExpressionTests extends ESIntegTestCase { vars.put("a", 1); vars.put("b", 3); vars.put("c", -1); - ees = new ExpressionExecutableScript(compiledScript, vars); + ees = new ExpressionExecutableScript(expr, vars); ees.run(); fail("A variable was allowed to be set that does not exist in the expression."); } catch (GeneralScriptException se) { @@ -558,7 +556,7 @@ public class MoreExpressionTests extends ESIntegTestCase { vars.put("a", 1); vars.put("b", 3); vars.put("xyz", "hello"); - ees = new ExpressionExecutableScript(compiledScript, vars); + ees = new ExpressionExecutableScript(expr, vars); ees.run(); fail("A non-number was allowed to be use in the expression."); } catch (GeneralScriptException se) { diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngine.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngine.java index 28ba360025..e31b97099f 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngine.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngine.java @@ -27,10 +27,7 @@ import org.apache.logging.log4j.util.Supplier; import org.elasticsearch.SpecialPermission; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.io.FastStringReader; -import org.elasticsearch.common.io.UTF8StreamWriter; -import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.logging.ESLoggerFactory; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.GeneralScriptException; import org.elasticsearch.script.Script; @@ -40,7 +37,6 @@ import org.elasticsearch.search.lookup.SearchLookup; import java.io.Reader; import java.io.StringWriter; -import java.lang.ref.SoftReference; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; @@ -86,14 +82,12 @@ public final class MustacheScriptEngine implements ScriptEngine { } @Override - public ExecutableScript executable(CompiledScript compiledScript, - @Nullable Map<String, Object> vars) { - return new MustacheExecutableScript(compiledScript, vars); + public ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars) { + return new MustacheExecutableScript((Mustache) compiledScript, vars); } @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, - @Nullable Map<String, Object> vars) { + public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { throw new UnsupportedOperationException(); } @@ -102,7 +96,7 @@ public final class MustacheScriptEngine implements ScriptEngine { * */ private class MustacheExecutableScript implements ExecutableScript { /** Compiled template object wrapper. */ - private CompiledScript template; + private Mustache template; /** Parameters to fill above object with. */ private Map<String, Object> vars; @@ -110,7 +104,7 @@ public final class MustacheScriptEngine implements ScriptEngine { * @param template the compiled template object wrapper * @param vars the parameters to fill above object with **/ - MustacheExecutableScript(CompiledScript template, Map<String, Object> vars) { + MustacheExecutableScript(Mustache template, Map<String, Object> vars) { this.template = template; this.vars = vars == null ? Collections.emptyMap() : vars; } @@ -127,7 +121,7 @@ public final class MustacheScriptEngine implements ScriptEngine { // crazy reflection here SpecialPermission.check(); AccessController.doPrivileged((PrivilegedAction<Void>) () -> { - ((Mustache) template.compiled()).execute(writer, vars); + template.execute(writer, vars); return null; }); } catch (Exception e) { diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java index 90678aba85..ca25147405 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java @@ -27,7 +27,6 @@ import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.NamedXContentRegistry; @@ -39,14 +38,13 @@ import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.template.CompiledTemplate; -import org.elasticsearch.template.CompiledTemplate; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import java.io.IOException; import java.util.Collections; -import static org.elasticsearch.script.ScriptContext.SEARCH; +import static org.elasticsearch.script.ScriptContext.EXECUTABLE; public class TransportSearchTemplateAction extends HandledTransportAction<SearchTemplateRequest, SearchTemplateResponse> { @@ -102,7 +100,7 @@ public class TransportSearchTemplateAction extends HandledTransportAction<Search NamedXContentRegistry xContentRegistry) throws IOException { Script script = new Script(searchTemplateRequest.getScriptType(), TEMPLATE_LANG, searchTemplateRequest.getScript(), searchTemplateRequest.getScriptParams() == null ? Collections.emptyMap() : searchTemplateRequest.getScriptParams()); - CompiledTemplate compiledScript = scriptService.compileTemplate(script, SEARCH); + CompiledTemplate compiledScript = scriptService.compileTemplate(script, EXECUTABLE); String source = compiledScript.run(script.getParams()); response.setSource(new BytesArray(source)); diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/CustomMustacheFactoryTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/CustomMustacheFactoryTests.java index eab96a4e99..7676442427 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/CustomMustacheFactoryTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/CustomMustacheFactoryTests.java @@ -20,8 +20,6 @@ package org.elasticsearch.script.mustache; import com.github.mustachejava.Mustache; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptEngine; @@ -31,7 +29,6 @@ import java.util.Map; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; -import static org.elasticsearch.script.ScriptType.INLINE; import static org.elasticsearch.script.mustache.CustomMustacheFactory.JSON_MIME_TYPE; import static org.elasticsearch.script.mustache.CustomMustacheFactory.PLAIN_TEXT_MIME_TYPE; import static org.elasticsearch.script.mustache.CustomMustacheFactory.X_WWW_FORM_URLENCODED_MIME_TYPE; @@ -65,9 +62,8 @@ public class CustomMustacheFactoryTests extends ESTestCase { final Map<String, String> params = randomBoolean() ? singletonMap(Script.CONTENT_TYPE_OPTION, JSON_MIME_TYPE) : emptyMap(); Mustache script = (Mustache) engine.compile(null, "{\"field\": \"{{value}}\"}", params); - CompiledScript compiled = new CompiledScript(INLINE, null, MustacheScriptEngine.NAME, script); - ExecutableScript executable = engine.executable(compiled, singletonMap("value", "a \"value\"")); + ExecutableScript executable = engine.executable(script, singletonMap("value", "a \"value\"")); assertThat(executable.run(), equalTo("{\"field\": \"a \\\"value\\\"\"}")); } @@ -76,9 +72,8 @@ public class CustomMustacheFactoryTests extends ESTestCase { final Map<String, String> params = singletonMap(Script.CONTENT_TYPE_OPTION, PLAIN_TEXT_MIME_TYPE); Mustache script = (Mustache) engine.compile(null, "{\"field\": \"{{value}}\"}", params); - CompiledScript compiled = new CompiledScript(INLINE, null, MustacheScriptEngine.NAME, script); - ExecutableScript executable = engine.executable(compiled, singletonMap("value", "a \"value\"")); + ExecutableScript executable = engine.executable(script, singletonMap("value", "a \"value\"")); assertThat(executable.run(), equalTo("{\"field\": \"a \"value\"\"}")); } @@ -87,9 +82,8 @@ public class CustomMustacheFactoryTests extends ESTestCase { final Map<String, String> params = singletonMap(Script.CONTENT_TYPE_OPTION, X_WWW_FORM_URLENCODED_MIME_TYPE); Mustache script = (Mustache) engine.compile(null, "{\"field\": \"{{value}}\"}", params); - CompiledScript compiled = new CompiledScript(INLINE, null, MustacheScriptEngine.NAME, script); - ExecutableScript executable = engine.executable(compiled, singletonMap("value", "tilde~ AND date:[2016 FROM*]")); + ExecutableScript executable = engine.executable(script, singletonMap("value", "tilde~ AND date:[2016 FROM*]")); assertThat(executable.run(), equalTo("{\"field\": \"tilde%7E+AND+date%3A%5B2016+FROM*%5D\"}")); } } diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheScriptEngineTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheScriptEngineTests.java index 30cf1fa04a..61cad62afb 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheScriptEngineTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheScriptEngineTests.java @@ -20,13 +20,10 @@ package org.elasticsearch.script.mustache; import com.github.mustachejava.MustacheFactory; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptType; import org.elasticsearch.test.ESTestCase; import org.junit.Before; @@ -58,8 +55,7 @@ public class MustacheScriptEngineTests extends ESTestCase { + "\"negative\": {\"term\": {\"body\": {\"value\": \"solr\"}" + "}}, \"negative_boost\": {{boost_val}} } }}"; Map<String, Object> vars = new HashMap<>(); vars.put("boost_val", "0.3"); - String o = (String) qe.executable(new CompiledScript(ScriptType.INLINE, "", "mustache", - qe.compile(null, template, compileParams)), vars).run(); + String o = (String) qe.executable(qe.compile(null, template, compileParams), vars).run(); assertEquals("GET _search {\"query\": {\"boosting\": {\"positive\": {\"match\": {\"body\": \"gift\"}}," + "\"negative\": {\"term\": {\"body\": {\"value\": \"solr\"}}}, \"negative_boost\": 0.3 } }}", o); @@ -70,8 +66,7 @@ public class MustacheScriptEngineTests extends ESTestCase { Map<String, Object> vars = new HashMap<>(); vars.put("boost_val", "0.3"); vars.put("body_val", "\"quick brown\""); - String o = (String) qe.executable(new CompiledScript(ScriptType.INLINE, "", "mustache", - qe.compile(null, template, compileParams)), vars).run(); + String o = (String) qe.executable(qe.compile(null, template, compileParams), vars).run(); assertEquals("GET _search {\"query\": {\"boosting\": {\"positive\": {\"match\": {\"body\": \"gift\"}}," + "\"negative\": {\"term\": {\"body\": {\"value\": \"\\\"quick brown\\\"\"}}}, \"negative_boost\": 0.3 } }}", o); @@ -86,9 +81,8 @@ public class MustacheScriptEngineTests extends ESTestCase { + "}"; XContentParser parser = createParser(JsonXContent.jsonXContent, templateString); Script script = Script.parse(parser); - CompiledScript compiledScript = new CompiledScript(ScriptType.INLINE, null, "mustache", - qe.compile(null, script.getIdOrCode(), Collections.emptyMap())); - ExecutableScript executableScript = qe.executable(compiledScript, script.getParams()); + Object compiled = qe.compile(null, script.getIdOrCode(), Collections.emptyMap()); + ExecutableScript executableScript = qe.executable(compiled, script.getParams()); assertThat(executableScript.run(), equalTo("{\"match_all\":{}}")); } @@ -102,9 +96,8 @@ public class MustacheScriptEngineTests extends ESTestCase { + "}"; XContentParser parser = createParser(JsonXContent.jsonXContent, templateString); Script script = Script.parse(parser); - CompiledScript compiledScript = new CompiledScript(ScriptType.INLINE, null, "mustache", - qe.compile(null, script.getIdOrCode(), Collections.emptyMap())); - ExecutableScript executableScript = qe.executable(compiledScript, script.getParams()); + Object compiled = qe.compile(null, script.getIdOrCode(), Collections.emptyMap()); + ExecutableScript executableScript = qe.executable(compiled, script.getParams()); assertThat(executableScript.run(), equalTo("{ \"match_all\":{} }")); } diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheTests.java index 316910a5cd..366fd2c034 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheTests.java @@ -21,10 +21,8 @@ package org.elasticsearch.script.mustache; import com.github.mustachejava.Mustache; import com.github.mustachejava.MustacheException; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.test.ESTestCase; @@ -44,7 +42,6 @@ import java.util.Set; import static java.util.Collections.singleton; import static java.util.Collections.singletonMap; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; -import static org.elasticsearch.script.ScriptType.INLINE; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -65,8 +62,7 @@ public class MustacheTests extends ESTestCase { Map<String, Object> params = Collections.singletonMap("boost_val", "0.2"); Mustache mustache = (Mustache) engine.compile(null, template, Collections.emptyMap()); - CompiledScript compiledScript = new CompiledScript(INLINE, "my-name", "mustache", mustache); - ExecutableScript result = engine.executable(compiledScript, params); + ExecutableScript result = engine.executable(mustache, params); assertEquals( "Mustache templating broken", "GET _search {\"query\": {\"boosting\": {\"positive\": {\"match\": {\"body\": \"gift\"}}," @@ -77,7 +73,7 @@ public class MustacheTests extends ESTestCase { public void testArrayAccess() throws Exception { String template = "{{data.0}} {{data.1}}"; - CompiledScript mustache = new CompiledScript(INLINE, "inline", "mustache", engine.compile(null, template, Collections.emptyMap())); + Object mustache = engine.compile(null, template, Collections.emptyMap()); Map<String, Object> vars = new HashMap<>(); Object data = randomFrom( new String[] { "foo", "bar" }, @@ -97,7 +93,7 @@ public class MustacheTests extends ESTestCase { public void testArrayInArrayAccess() throws Exception { String template = "{{data.0.0}} {{data.0.1}}"; - CompiledScript mustache = new CompiledScript(INLINE, "inline", "mustache", engine.compile(null, template, Collections.emptyMap())); + Object mustache = engine.compile(null, template, Collections.emptyMap()); Map<String, Object> vars = new HashMap<>(); Object data = randomFrom( new String[][] { new String[] { "foo", "bar" }}, @@ -110,7 +106,7 @@ public class MustacheTests extends ESTestCase { public void testMapInArrayAccess() throws Exception { String template = "{{data.0.key}} {{data.1.key}}"; - CompiledScript mustache = new CompiledScript(INLINE, "inline", "mustache", engine.compile(null, template, Collections.emptyMap())); + Object mustache = engine.compile(null, template, Collections.emptyMap()); Map<String, Object> vars = new HashMap<>(); Object data = randomFrom( new Object[] { singletonMap("key", "foo"), singletonMap("key", "bar") }, @@ -134,7 +130,7 @@ public class MustacheTests extends ESTestCase { List<String> randomList = Arrays.asList(generateRandomStringArray(10, 20, false)); String template = "{{data.array.size}} {{data.list.size}}"; - CompiledScript mustache = new CompiledScript(INLINE, "inline", "mustache", engine.compile(null, template, Collections.emptyMap())); + Object mustache = engine.compile(null, template, Collections.emptyMap()); Map<String, Object> data = new HashMap<>(); data.put("array", randomArrayValues); data.put("list", randomList); @@ -376,7 +372,7 @@ public class MustacheTests extends ESTestCase { } private void assertScript(String script, Map<String, Object> vars, Matcher<Object> matcher) { - Object result = engine.executable(new CompiledScript(INLINE, "inline", "mustache", compile(script)), vars).run(); + Object result = engine.executable(compile(script), vars).run(); assertThat(result, matcher); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java index aa30302f2a..1fd76aef8f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java @@ -24,10 +24,8 @@ import org.elasticsearch.SpecialPermission; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.painless.Compiler.Loader; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.LeafSearchScript; -import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.SearchScript; @@ -177,8 +175,8 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr * @return An {@link ExecutableScript} with the currently specified variables. */ @Override - public ExecutableScript executable(final CompiledScript compiledScript, final Map<String, Object> vars) { - return new ScriptImpl((GenericElasticsearchScript) compiledScript.compiled(), vars, null); + public ExecutableScript executable(final Object compiledScript, final Map<String, Object> vars) { + return new ScriptImpl((GenericElasticsearchScript) compiledScript, vars, null); } /** @@ -189,7 +187,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr * @return An {@link SearchScript} with the currently specified variables. */ @Override - public SearchScript search(final CompiledScript compiledScript, final SearchLookup lookup, final Map<String, Object> vars) { + public SearchScript search(final Object compiledScript, final SearchLookup lookup, final Map<String, Object> vars) { return new SearchScript() { /** * Get the search script that will have access to search field values. @@ -198,7 +196,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr */ @Override public LeafSearchScript getLeafSearchScript(final LeafReaderContext context) throws IOException { - return new ScriptImpl((GenericElasticsearchScript) compiledScript.compiled(), vars, lookup.getLeafSearchLookup(context)); + return new ScriptImpl((GenericElasticsearchScript) compiledScript, vars, lookup.getLeafSearchLookup(context)); } /** @@ -206,7 +204,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr */ @Override public boolean needsScores() { - return ((GenericElasticsearchScript) compiledScript.compiled()).uses$_score(); + return ((GenericElasticsearchScript) compiledScript).uses$_score(); } }; } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/NeedsScoreTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/NeedsScoreTests.java index 1c729053d7..42d7984e64 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/NeedsScoreTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/NeedsScoreTests.java @@ -21,8 +21,6 @@ package org.elasticsearch.painless; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexService; -import org.elasticsearch.script.CompiledScript; -import org.elasticsearch.script.ScriptType; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -42,23 +40,19 @@ public class NeedsScoreTests extends ESSingleNodeTestCase { SearchLookup lookup = new SearchLookup(index.mapperService(), index.fieldData(), null); Object compiled = service.compile(null, "1.2", Collections.emptyMap()); - SearchScript ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled), - lookup, Collections.<String, Object>emptyMap()); + SearchScript ss = service.search(compiled, lookup, Collections.emptyMap()); assertFalse(ss.needsScores()); compiled = service.compile(null, "doc['d'].value", Collections.emptyMap()); - ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled), - lookup, Collections.<String, Object>emptyMap()); + ss = service.search(compiled, lookup, Collections.emptyMap()); assertFalse(ss.needsScores()); compiled = service.compile(null, "1/_score", Collections.emptyMap()); - ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled), - lookup, Collections.<String, Object>emptyMap()); + ss = service.search(compiled, lookup, Collections.emptyMap()); assertTrue(ss.needsScores()); compiled = service.compile(null, "doc['d'].value * _score", Collections.emptyMap()); - ss = service.search(new CompiledScript(ScriptType.INLINE, "randomName", "painless", compiled), - lookup, Collections.<String, Object>emptyMap()); + ss = service.search(compiled, lookup, Collections.emptyMap()); assertTrue(ss.needsScores()); } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptEngineTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptEngineTests.java index 89385c8862..fe588a3fc3 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptEngineTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptEngineTests.java @@ -19,9 +19,7 @@ package org.elasticsearch.painless; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; -import org.elasticsearch.script.ScriptType; import java.util.Arrays; import java.util.Collections; @@ -83,8 +81,7 @@ public class ScriptEngineTests extends ScriptTestCase { Object compiledScript = scriptEngine.compile(null, "return ctx.value;", Collections.emptyMap()); - ExecutableScript script = scriptEngine.executable(new CompiledScript(ScriptType.INLINE, - "testChangingVarsCrossExecution1", "painless", compiledScript), vars); + ExecutableScript script = scriptEngine.executable(compiledScript, vars); ctx.put("value", 1); Object o = script.run(); @@ -99,8 +96,7 @@ public class ScriptEngineTests extends ScriptTestCase { Map<String, Object> vars = new HashMap<>(); Object compiledScript = scriptEngine.compile(null, "return params['value'];", Collections.emptyMap()); - ExecutableScript script = scriptEngine.executable(new CompiledScript(ScriptType.INLINE, - "testChangingVarsCrossExecution2", "painless", compiledScript), vars); + ExecutableScript script = scriptEngine.executable(compiledScript, vars); script.setNextVar("value", 1); Object value = script.run(); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java index 27d7c5c94b..ccc3f381e0 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java @@ -25,10 +25,8 @@ import org.apache.lucene.search.Scorer; import org.elasticsearch.common.lucene.ScorerAware; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.painless.antlr.Walker; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptException; -import org.elasticsearch.script.ScriptType; import org.elasticsearch.test.ESTestCase; import org.junit.Before; @@ -87,8 +85,7 @@ public abstract class ScriptTestCase extends ESTestCase { definition, null); } // test actual script execution - Object object = scriptEngine.compile(null, script, compileParams); - CompiledScript compiled = new CompiledScript(ScriptType.INLINE, getTestName(), "painless", object); + Object compiled = scriptEngine.compile(null, script, compileParams); ExecutableScript executableScript = scriptEngine.executable(compiled, vars); if (scorer != null) { ((ScorerAware)executableScript).setScorer(scorer); diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollAction.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollAction.java index 694c00e5c6..5fcc23e06a 100644 --- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollAction.java +++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollAction.java @@ -49,7 +49,6 @@ import org.elasticsearch.index.mapper.RoutingFieldMapper; import org.elasticsearch.index.mapper.SourceFieldMapper; import org.elasticsearch.index.mapper.TypeFieldMapper; import org.elasticsearch.index.mapper.VersionFieldMapper; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; @@ -773,8 +772,8 @@ public abstract class AbstractAsyncBulkByScrollAction<Request extends AbstractBu return request; } if (executable == null) { - CompiledScript compiled = scriptService.compile(script, ScriptContext.UPDATE); - executable = scriptService.executable(compiled, params); + ExecutableScript.Compiled compiled = scriptService.compile(script, ScriptContext.UPDATE); + executable = compiled.newInstance(params); } if (context == null) { context = new HashMap<>(); diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollActionScriptTestCase.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollActionScriptTestCase.java index 6ddf6daa88..5058244d07 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollActionScriptTestCase.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AbstractAsyncBulkByScrollActionScriptTestCase.java @@ -24,11 +24,10 @@ import org.elasticsearch.index.reindex.AbstractAsyncBulkByScrollAction.OpType; import org.elasticsearch.index.reindex.AbstractAsyncBulkByScrollAction.RequestWrapper; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; import org.junit.Before; -import org.mockito.Matchers; import java.util.Map; import java.util.function.Consumer; @@ -36,6 +35,7 @@ import java.util.function.Consumer; import static java.util.Collections.singletonMap; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -56,9 +56,9 @@ public abstract class AbstractAsyncBulkByScrollActionScriptTestCase< IndexRequest index = new IndexRequest("index", "type", "1").source(singletonMap("foo", "bar")); ScrollableHitSource.Hit doc = new ScrollableHitSource.BasicHit("test", "type", "id", 0); ExecutableScript executableScript = new SimpleExecutableScript(scriptBody); - - when(scriptService.executable(any(CompiledScript.class), Matchers.<Map<String, Object>>any())) - .thenReturn(executableScript); + ExecutableScript.Compiled compiled = params -> executableScript; + when(scriptService.compile(any(), eq(ScriptContext.EXECUTABLE))).thenReturn(compiled); + when(scriptService.compile(any(), eq(ScriptContext.UPDATE))).thenReturn(compiled); AbstractAsyncBulkByScrollAction<Request> action = action(scriptService, request().setScript(mockScript(""))); RequestWrapper<?> result = action.buildScriptApplier().apply(AbstractAsyncBulkByScrollAction.wrap(index), doc); return (result != null) ? (T) result.self() : null; diff --git a/plugins/examples/script-expert-scoring/src/main/java/org/elasticsearch/example/expertscript/ExpertScriptPlugin.java b/plugins/examples/script-expert-scoring/src/main/java/org/elasticsearch/example/expertscript/ExpertScriptPlugin.java index 8a13b2fed7..1c0977ca8f 100644 --- a/plugins/examples/script-expert-scoring/src/main/java/org/elasticsearch/example/expertscript/ExpertScriptPlugin.java +++ b/plugins/examples/script-expert-scoring/src/main/java/org/elasticsearch/example/expertscript/ExpertScriptPlugin.java @@ -22,18 +22,15 @@ package org.elasticsearch.example.expertscript; import java.io.IOException; import java.io.UncheckedIOException; import java.util.Map; -import java.util.Objects; import java.util.function.Function; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; -import org.apache.lucene.search.Scorer; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.ScriptPlugin; -import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.ScriptEngine; @@ -123,13 +120,13 @@ public class ExpertScriptPlugin extends Plugin implements ScriptPlugin { @Override @SuppressWarnings("unchecked") - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> params) { - Function<Map<String,Object>,SearchScript> scriptFactory = (Function<Map<String,Object>,SearchScript>) compiledScript.compiled(); + public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> params) { + Function<Map<String,Object>,SearchScript> scriptFactory = (Function<Map<String,Object>,SearchScript>) compiledScript; return scriptFactory.apply(params); } @Override - public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> params) { + public ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> params) { throw new UnsupportedOperationException(); } diff --git a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java index d685a9f951..3cfc55f39b 100644 --- a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java +++ b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java @@ -67,7 +67,7 @@ public class MockScriptEngine implements ScriptEngine { } @Override - public Object compile(String name, String source, Map<String, String> params) { + public Object compile(String name, String source, Map<String, String> options) { // Scripts are always resolved using the script's source. For inline scripts, it's easy because they don't have names and the // source is always provided. For stored and file scripts, the source of the script must match the key of a predefined script. Function<Map<String, Object>, Object> script = scripts.get(source); @@ -75,18 +75,18 @@ public class MockScriptEngine implements ScriptEngine { throw new IllegalArgumentException("No pre defined script matching [" + source + "] for script with name [" + name + "], " + "did you declare the mocked script?"); } - return new MockCompiledScript(name, params, source, script); + return new MockCompiledScript(name, options, source, script); } @Override - public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) { - MockCompiledScript compiled = (MockCompiledScript) compiledScript.compiled(); + public ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars) { + MockCompiledScript compiled = (MockCompiledScript) compiledScript; return compiled.createExecutableScript(vars); } @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { - MockCompiledScript compiled = (MockCompiledScript) compiledScript.compiled(); + public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) { + MockCompiledScript compiled = (MockCompiledScript) compiledScript; return compiled.createSearchScript(vars, lookup); } |