使用elastic4s 7.17.2合并ES文档时脚本编译错误求助
问题原因及解决方案
核心原因
你写的脚本使用了Groovy语法,但Elasticsearch 7.17默认采用Painless脚本语言,两者语法不兼容,导致脚本编译失败。同时请求返回found: false,说明目标文档不存在,默认情况下Update操作不会自动创建文档,这也会影响最终执行结果,但当前首要问题是脚本语法错误。
具体语法问题及修正
- 函数定义:Painless要求函数必须明确参数类型(或用
def声明动态类型),返回类型也需指定(或用def) - 类型判断:Painless中判断对象类型用
instanceof,需引用正确的全限定类型(如java.util.Map) - 循环遍历:Painless中遍历Map的entrySet需使用Java风格的for循环语法
- Map元素操作:Painless中推荐用
get()/put()方法操作Map元素,比直接用[]更规范
修正后的Painless脚本:
def merge(def s, def t) { if (s == null) { return t; } if (!(t instanceof java.util.Map)) { return s; } for (java.util.Map.Entry entry : t.entrySet()) { def key = entry.getKey(); def value = entry.getValue(); s.put(key, merge(s.get(key), value)); } return s; } ctx._source = merge(ctx._source, params);
Elastic4s代码调整
若需要在目标文档不存在时自动创建,需添加docAsUpsert(true)配置,修正后的代码如下:
override val request: UpdateRequest = { val retryCount = 5 val mergeScript = """ |def merge(def s, def t) { | if (s == null) { | return t; | } | if (!(t instanceof java.util.Map)) { | return s; | } | | for (java.util.Map.Entry entry : t.entrySet()) { | def key = entry.getKey(); | def value = entry.getValue(); | s.put(key, merge(s.get(key), value)); | } | | return s; |} | |ctx._source = merge(ctx._source, params); |""".stripMargin updateById(index, id) .retryOnConflict(retryCount) .script( Script(mergeScript).params(Map("param1" -> "100", "param2" -> "5")) ) .docAsUpsert(true) // 文档不存在时自动创建 }
额外说明
- 若坚持使用Groovy脚本,需在Elasticsearch配置中修改
script.allowed_types添加groovy,并开启script.groovy.sandbox.enabled,但Groovy在Elasticsearch高版本中已被逐步废弃,不推荐使用。 - 查看Elasticsearch节点日志可获取更详细的脚本编译错误细节,便于精准定位语法问题。
内容的提问来源于stack exchange,提问作者Amit Levizky
相关产品推荐
相关产品推荐

