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 c3d27b5d615..55ba778d012 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryRewriteContext.java @@ -137,6 +137,10 @@ public class QueryRewriteContext implements ParseFieldMatcherSupplier { this.executionMode.set(Boolean.TRUE); } + /** + * This method fails if {@link #setExecutionMode()} is called before on this context. + * This is used to seal + */ protected void failIfExecutionMode() { this.cachable = false; if (executionMode.get() == Boolean.TRUE) { 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 3869ecfd2c1..d15c69e088e 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -335,11 +335,17 @@ public class QueryShardContext extends QueryRewriteContext { return indexSettings.getIndex(); } + /** + * Compiles (or retrieves from cache) and executes the provided script + */ public SearchScript getSearchScript(Script script, ScriptContext context, Map params) { failIfExecutionMode(); return scriptService.search(lookup(), script, context, params); } - + /** + * Returns a lazily created {@link SearchScript} that is compiled immediately but can be pulled later once all + * parameters are available. + */ public Function, SearchScript> getLazySearchScript(Script script, ScriptContext context, Map params) { failIfExecutionMode(); @@ -347,11 +353,18 @@ public class QueryShardContext extends QueryRewriteContext { return (p) -> scriptService.search(lookup(), compile, p); } + /** + * Compiles (or retrieves from cache) and executes the provided script + */ public ExecutableScript getExecutableScript(Script script, ScriptContext context, Map params) { failIfExecutionMode(); return scriptService.executable(script, context, params); } + /** + * Returns a lazily created {@link ExecutableScript} that is compiled immediately but can be pulled later once all + * parameters are available. + */ public Function, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context, Map params) { failIfExecutionMode(); diff --git a/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java b/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java index 26af6d85d06..f8299693dcf 100644 --- a/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java +++ b/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java @@ -172,6 +172,13 @@ final class DefaultSearchContext extends SearchContext { queryShardContext.setTypes(request.types()); } + DefaultSearchContext(DefaultSearchContext source) { + this(source.id(), source.request(), source.shardTarget(), source.engineSearcher, source.indexService, source.indexShard(), + source.bigArrays(), source.timeEstimateCounter(), source.parseFieldMatcher(), source.timeout(), source.fetchPhase()); + } + + + @Override public void doClose() { // clear and scope phase we have diff --git a/core/src/main/java/org/elasticsearch/search/SearchService.java b/core/src/main/java/org/elasticsearch/search/SearchService.java index 186ea231847..ff6a359f0b0 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchService.java +++ b/core/src/main/java/org/elasticsearch/search/SearchService.java @@ -517,11 +517,18 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv } final SearchContext createContext(ShardSearchRequest request, @Nullable Engine.Searcher searcher) throws IOException { - - DefaultSearchContext context = createSearchContext(request, defaultSearchTimeout, searcher); - SearchContext.setCurrent(context); + final DefaultSearchContext context = createSearchContext(request, defaultSearchTimeout, searcher); try { - request.rewrite(new QueryShardContext(context.getQueryShardContext())); + // we clone the search context here just for rewriting otherwise we + // might end up with incorrect state since we are using now() or script services + // during rewrite and normalized / evaluate templates etc. + // NOTE this context doesn't need to be closed - the outer context will + // take care of this. + DefaultSearchContext rewriteContext = new DefaultSearchContext(context); + SearchContext.setCurrent(rewriteContext); + request.rewrite(rewriteContext.getQueryShardContext()); + SearchContext.setCurrent(context); + assert context.getQueryShardContext().isCachable(); if (request.scroll() != null) { context.scrollContext(new ScrollContext()); context.scrollContext().scroll = request.scroll();