Java API调用ElasticSearch存储脚本更新报错,GUI执行正常求解决
Elasticsearch存储脚本调用错误排查:无法解析ctx._source.deviceId
问题背景
在Elasticsearch GUI中创建存储脚本chargepoint_device_status_update2,并通过_update_by_query接口执行更新逻辑(当updateTime大于laststatuschangeddate时更新文档,否则不操作)可正常运行,但使用Spring Boot的RestHighLevelClient编写Java代码调用时,出现编译错误,提示cannot resolve symbol [ctx._source.deviceId]。
GUI操作步骤
1. 创建存储脚本请求
POST _scripts/chargepoint_device_status_update2 { "script": { "source": "if (ctx._source.deviceId==params['deviceId'] && ctx._source.laststatuschangeddate<params['updateTime']) { ctx._source.statusName=params['newStatus'];ctx._source.laststatuschangeddate=params['updateTime'] } else { ctx.op = 'noop' }", "lang": "painless" } }
2. 执行更新请求
POST idx_chargepoint_device_status/_update_by_query { "script": { "id": "chargepoint_device_status_update2", "params": { "updateTime": 1668462920315, "newStatus": "available3", "deviceId": "52334" } } }
Java错误代码
@Autowired private RestHighLevelClient client; Map<String,Object> parameters=new HashMap<>(); parameters.put("updateTime",1668462920315L); parameters.put("newStatus","available3"); parameters.put("deviceId","52334"); Script script = new Script(ScriptType.STORED, null, "chargepoint_device_status_update2", parameters); QueryBuilder qb = new ScriptQueryBuilder(script); UpdateByQueryRequest request = new UpdateByQueryRequest("idx_chargepoint_device_status"); request.setQuery(qb); client.updateByQuery(request, RequestOptions.DEFAULT);
报错信息
OpenSearch exception [type=illegal_argument_exception, reason=cannot resolve symbol [ctx._source.deviceId]] Suppressed: org.opensearch.client.ResponseException: method [POST], host [http://localhost:9200], URI [/idx_chargepoint_device_status/_update_by_query?slices=1&requests_per_second=-1&ignore_unavailable=false&expand_wildcards=open&allow_no_indices=true&ignore_throttled=true&wait_for_completion=true&timeout=1m], status line [HTTP/1.1 400 Bad Request] {"error":{"root_cause":[{"type":"script_exception","reason":"compile error","script_stack":["if (ctx._source.deviceId==params['device ..."," ^---- HERE"],"script":"if (ctx._source.deviceId==params['deviceId'] && ctx._source.laststatuschangeddate<params['updateTime']) { ctx._source.statusName=params['newStatus'];ctx._source.laststatuschangeddate=params['updateTime'] } else { ctx.op = 'noop' }","lang":"painless","position":{"offset":15,"start":0,"end":40}}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"idx_chargepoint_device_status","node":"zMQFoB7kQ2eWVi3kEWOHWA","reason":{"type":"query_shard_exception","reason":"failed to create query: compile error","index":"idx_chargepoint_device_status","index_uuid":"UKGQ1wU7TFWkAKh9zgsmXw","caused_by":{"type":"script_exception","reason":"compile error","script_stack":["if (ctx._source.deviceId==params['device ..."," ^---- HERE"],"script":"if (ctx._source.deviceId==params['deviceId'] && ctx._source.laststatuschangeddate<params['updateTime']) { ctx._source.statusName=params['newStatus'];ctx._source.laststatuschangeddate=params['updateTime'] } else { ctx.op = 'noop' }","lang":"painless","position":{"offset":15,"start":0,"end":40},"caused_by":{"type":"illegal_argument_exception","reason":"cannot resolve symbol [ctx._source.deviceId]"}}}}],"caused_by":{"type":"script_exception","reason":"compile error","script_stack":["if (ctx._source.deviceId==params['device ..."," ^---- HERE"],"script":"if (ctx._source.deviceId==params['deviceId'] && ctx._source.laststatuschangeddate<params['updateTime']) { ctx._source.statusName=params['newStatus'];ctx._source.laststatuschangeddate=params['updateTime'] } else { ctx.op = 'noop' }","lang":"painless","position":{"offset":15,"start":0,"end":40},"caused_by":{"type":"illegal_argument_exception","reason":"cannot resolve symbol [ctx._source.deviceId]"}}},"status":400}
错误原因
你错误地将更新脚本当作了查询脚本使用:
ScriptQueryBuilder是用于搜索阶段的脚本查询,该上下文不存在ctx._source对象,因此无法解析ctx._source.deviceId。- 而
_update_by_query接口的正确用法是将脚本设置为更新逻辑,而非查询条件。
修正后的Java代码
@Autowired private RestHighLevelClient client; Map<String,Object> parameters=new HashMap<>(); parameters.put("updateTime",1668462920315L); parameters.put("newStatus","available3"); parameters.put("deviceId","52334"); Script script = new Script(ScriptType.STORED, null, "chargepoint_device_status_update2", parameters); UpdateByQueryRequest request = new UpdateByQueryRequest("idx_chargepoint_device_status"); // 直接将脚本设置为更新逻辑,而非查询条件 request.setScript(script); client.updateByQuery(request, RequestOptions.DEFAULT);
内容的提问来源于stack exchange,提问作者Anthony Brown
相关产品推荐
相关产品推荐

