Elasticsearch 8.10中Painless脚本for循环查询失效问题
问题分析与解决方案
你的问题出在Painless脚本中对多值字段的访问方式错误:原脚本使用.length属性获取数组长度,并用[i]直接访问元素,但对于Elasticsearch的多值字段,doc['field']返回的是DocValuesIterable类型,需要用.size()获取长度,.get(i)获取对应位置的元素。
另外,也可以直接通过params._source访问文档的原始字段值,这种方式对数组的访问更直观,无需适配DocValues的特殊API。
修正后的脚本方案1(使用doc字段的正确API)
将查询脚本修改为以下内容:
GET target_index/_search { "query": { "script": { "script": { "lang": "painless", "source": """ double userCriteria = params.userTarget.seniority; // 使用size()获取多值字段的元素数量 if (doc['targetoperator'].size() > 0) { for (int i = 0; i < doc['targetoperator'].size(); ++i) { // 用get(i)获取多值字段的第i个元素 String op = doc['targetoperator'].get(i); double val = doc['targetvalue'].get(i); if (op == "<=") { if (!(userCriteria <= val)) { return false; } } else if (op == ">") { if (!(userCriteria > val)) { return false; } } else if (op == "==") { if (!(userCriteria == val)) { return false; } } } } return true; """, "params": { "userTarget": { "gender": "male", "seniority": 5 } } } } }, "_source": [ "targetoperator", "targetvalue" ] }
修正后的脚本方案2(使用params._source访问原始字段)
这种方式更贴近常规的数组访问逻辑,代码可读性更高:
GET target_index/_search { "query": { "script": { "script": { "lang": "painless", "source": """ double userCriteria = params.userTarget.seniority; // 直接访问文档原始的数组字段 if (params._source.targetoperator != null && params._source.targetoperator.length > 0) { for (int i = 0; i < params._source.targetoperator.length; ++i) { String op = params._source.targetoperator[i]; double val = params._source.targetvalue[i]; if (op.equals("<=")) { if (!(userCriteria <= val)) { return false; } } else if (op.equals(">")) { if (!(userCriteria > val)) { return false; } } else if (op.equals("==")) { if (!(userCriteria == val)) { return false; } } } } return true; """, "params": { "userTarget": { "gender": "male", "seniority": 5 } } } } }, "_source": [ "targetoperator", "targetvalue" ] }
验证说明
修改后执行查询,seniority=5会同时满足>4和<=8两个条件,脚本返回true,因此会匹配到目标文档。
内容的提问来源于stack exchange,提问作者Duy Tran
相关产品推荐
相关产品推荐

