/** Can the shard request be cached at all? */ public boolean canCache(ShardSearchRequest request, SearchContext context) { // TODO: for now, template is not supported, though we could use the generated bytes as the key if (hasLength(request.templateSource())) { return false; } // for now, only enable it for requests with no hits if (context.size() != 0) { return false; } // We cannot cache with DFS because results depend not only on the content of the index but also // on the overridden statistics. So if you ran two queries on the same index with different // stats // (because an other shard was updated) you would get wrong results because of the scores // (think about top_hits aggs or scripts using the score) if (!CACHEABLE_SEARCH_TYPES.contains(context.searchType())) { return false; } IndexMetaData index = clusterService.state().getMetaData().index(request.index()); if (index == null) { // in case we didn't yet have the cluster state, or it just got deleted return false; } // if not explicitly set in the request, use the index setting, if not, use the request if (request.requestCache() == null) { if (!isCacheEnabled(index.settings(), Boolean.FALSE)) { return false; } } else if (!request.requestCache()) { return false; } // if the reader is not a directory reader, we can't get the version from it if (!(context.searcher().getIndexReader() instanceof DirectoryReader)) { return false; } // if now in millis is used (or in the future, a more generic "isDeterministic" flag // then we can't cache based on "now" key within the search request, as it is not deterministic if (context.nowInMillisUsed()) { return false; } return true; }
private void parseTemplate(ShardSearchRequest request) { BytesReference processedQuery; if (request.template() != null) { ExecutableScript executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH); processedQuery = (BytesReference) executable.run(); } else { if (!hasLength(request.templateSource())) { return; } XContentParser parser = null; Template template = null; try { parser = XContentFactory.xContent(request.templateSource()) .createParser(request.templateSource()); template = TemplateQueryParser.parse(parser, "params", "template"); if (template.getType() == ScriptService.ScriptType.INLINE) { // Try to double parse for nested template id/file parser = null; try { ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); processedQuery = (BytesReference) executable.run(); parser = XContentFactory.xContent(processedQuery).createParser(processedQuery); } catch (ElasticsearchParseException epe) { // This was an non-nested template, the parse failure was due to this, it is safe to // assume this refers to a file // for backwards compatibility and keep going template = new Template( template.getScript(), ScriptService.ScriptType.FILE, MustacheScriptEngineService.NAME, null, template.getParams()); ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); processedQuery = (BytesReference) executable.run(); } if (parser != null) { try { Template innerTemplate = TemplateQueryParser.parse(parser); if (hasLength(innerTemplate.getScript()) && !innerTemplate.getType().equals(ScriptService.ScriptType.INLINE)) { // An inner template referring to a filename or id template = new Template( innerTemplate.getScript(), innerTemplate.getType(), MustacheScriptEngineService.NAME, null, template.getParams()); ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); processedQuery = (BytesReference) executable.run(); } } catch (ScriptParseException e) { // No inner template found, use original template from above } } } else { ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); processedQuery = (BytesReference) executable.run(); } } catch (IOException e) { throw new ElasticsearchParseException("Failed to parse template", e); } finally { Releasables.closeWhileHandlingException(parser); } if (!hasLength(template.getScript())) { throw new ElasticsearchParseException("Template must have [template] field configured"); } } request.source(processedQuery); }