使用脚本引擎的高级脚本
编辑使用脚本引擎的高级脚本编辑
ScriptEngine
是用于实现脚本语言的后端。它也可用于编写需要使用脚本高级内部结构的脚本。例如,希望在评分时使用词频的脚本。
插件 文档 包含有关如何编写插件的更多信息,以便 Elasticsearch 能够正确加载它。要注册 ScriptEngine
,您的插件应实现 ScriptPlugin
接口并覆盖 getScriptEngine(Settings settings)
方法。
以下是一个自定义 ScriptEngine
的示例,它使用语言名称 expert_scripts
。它实现了一个名为 pure_df
的脚本,该脚本可用作搜索脚本,以将每个文档的分数覆盖为所提供词项的文档频率。
private static class MyExpertScriptEngine implements ScriptEngine { @Override public String getType() { return "expert_scripts"; } @Override public <T> T compile( String scriptName, String scriptSource, ScriptContext<T> context, Map<String, String> params ) { if (context.equals(ScoreScript.CONTEXT) == false) { throw new IllegalArgumentException(getType() + " scripts cannot be used for context [" + context.name + "]"); } // we use the script "source" as the script identifier if ("pure_df".equals(scriptSource)) { ScoreScript.Factory factory = new PureDfFactory(); return context.factoryClazz.cast(factory); } throw new IllegalArgumentException("Unknown script name " + scriptSource); } @Override public void close() { // optionally close resources } @Override public Set<ScriptContext<?>> getSupportedContexts() { return Set.of(ScoreScript.CONTEXT); } private static class PureDfFactory implements ScoreScript.Factory, ScriptFactory { @Override public boolean isResultDeterministic() { // PureDfLeafFactory only uses deterministic APIs, this // implies the results are cacheable. return true; } @Override public LeafFactory newFactory( Map<String, Object> params, SearchLookup lookup ) { return new PureDfLeafFactory(params, lookup); } } private static class PureDfLeafFactory implements LeafFactory { private final Map<String, Object> params; private final SearchLookup lookup; private final String field; private final String term; private PureDfLeafFactory( Map<String, Object> params, SearchLookup lookup) { if (params.containsKey("field") == false) { throw new IllegalArgumentException( "Missing parameter [field]"); } if (params.containsKey("term") == false) { throw new IllegalArgumentException( "Missing parameter [term]"); } this.params = params; this.lookup = lookup; field = params.get("field").toString(); term = params.get("term").toString(); } @Override public boolean needs_score() { return false; // Return true if the script needs the score } @Override public ScoreScript newInstance(DocReader docReader) throws IOException { DocValuesDocReader dvReader = DocValuesDocReader) docReader); PostingsEnum postings = dvReader.getLeafReaderContext() .reader().postings(new Term(field, term; if (postings == null) { /* * the field and/or term don't exist in this segment, * so always return 0 */ return new ScoreScript(params, lookup, docReader) { @Override public double execute( ExplanationHolder explanation ) { return 0.0d; } }; } return new ScoreScript(params, lookup, docReader) { int currentDocid = -1; @Override public void setDocument(int docid) { /* * advance has undefined behavior calling with * a docid <= its current docid */ if (postings.docID() < docid) { try { postings.advance(docid); } catch (IOException e) { throw new UncheckedIOException(e); } } currentDocid = docid; } @Override public double execute(ExplanationHolder explanation) { if (postings.docID() != currentDocid) { /* * advance moved past the current doc, so this * doc has no occurrences of the term */ return 0.0d; } try { return postings.freq(); } catch (IOException e) { throw new UncheckedIOException(e); } } }; } } }
您可以通过将脚本的 lang
指定为 expert_scripts
,并将脚本的名称指定为脚本源来执行脚本
POST /_search { "query": { "function_score": { "query": { "match": { "body": "foo" } }, "functions": [ { "script_score": { "script": { "source": "pure_df", "lang" : "expert_scripts", "params": { "field": "body", "term": "foo" } } } } ] } } }