背景介绍
在es6.5的javaapi中使用脚本进行打分控制的时候,无可避免的会使用到外部传参来进行打分,参考下面这样的方式
{
"script_score": {
"script": {
"source": "return (params.current_time - doc['create_time'].value)/86400",
"lang": "painless",
"params": {
"current_time": 1563974409
}
}
}
}
在上面的这段查询结构中,可以看到我通过params字段传入当前的时间戳,配合文档中的时间戳来计算距离当前时间戳过了几天。当然这只是一个例子,需要的就是先将这段简单的DSL在javaapi中实现出来,然后我们就可以向上面接着堆积木,撘逻辑了。
这里我们看官方文档对这部分API的样例,版本选择6.5
要传入参数首先需要声明Script对象,Script类的四个参数顺序是,脚本类型,脚本内容,脚本语言,参数。但是如果按照这个参数进行组装Script对象的,肯定会收到如下报错。
Caused by: org.elasticsearch.index.query.QueryShardException: script_score: the script could not be loaded
原因探究
查看Script构造函数看,可以看见Script的构造函数如下
/**
* Constructor for a script that does not need to use compiler options.
* @param type The {@link ScriptType}.
* @param lang The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* For {@link ScriptType#STORED} scripts this should be null, but can
* be specified to access scripts stored as part of the stored scripts deprecated API.
* @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#STORED}.
* The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* @param params The user-defined params to be bound for script execution.
*/
public Script(ScriptType type, String lang, String idOrCode, Map<String, Object> params) {
this(type, lang, idOrCode, type == ScriptType.INLINE ? Collections.emptyMap() : null, params);
}
很明显,lang(脚本类型,也就是painless)是在第二个位置的,难怪没有办法成功调用方法。es的官方文档给出的范例其实就是个错误示范。还是说可能在文档之后的版本变更?但至少这里需要注意了。
解决方案
在传参的时候调换位置即可正常编译脚本执行
Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, script_str, script_params);