Elasticsearch查询:如何过滤数组最后一个元素匹配指定值的文档
解决Elasticsearch脚本查询数组最后一个元素的错误问题
错误原因
你遇到的illegal_argument exception是因为values字段为text类型:Elasticsearch对text字段的doc访问会指向分词后的词项集合,而非原始的数组结构,且text字段默认不支持这类逐文档的脚本操作。同时,即便强行访问,doc['values']的顺序也不是原始数组的顺序,无法正确获取最后一个元素。
解决方案
方案1:修改字段映射(推荐,性能最优)
将values字段改为keyword类型(若无需分词),或添加keyword子字段(若需保留text分词功能),这样Elasticsearch会存储原始的数组结构,支持通过doc高效访问。
修改映射的请求示例:
PUT /你的索引名/_mapping { "properties": { "values": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }
(若不需要text分词功能,可直接把type设为keyword,省略fields部分)
修改后的查询脚本:
{ "query": { "bool": { "filter": { "script": { "script": { "source": "params.vs.contains(doc['values.keyword'][doc['values.keyword'].size() - 1])", "lang": "painless", "params": { "vs": ["a","b"] } } } } } } }
(如果直接把values设为keyword类型,把脚本里的values.keyword改成values即可)
方案2:不修改映射,通过_source访问原始数据(性能较差,适合小数据集)
如果无法修改索引映射,可以直接从文档的原始_source中读取数组,缺点是会加载整个文档的原始数据,数据量大时性能下降明显。
查询脚本示例:
{ "query": { "bool": { "filter": { "script": { "script": { "source": "def valuesArr = ctx._source.values; if (valuesArr == null || valuesArr.length == 0) return false; def lastVal = valuesArr[valuesArr.length - 1]; return params.vs.contains(lastVal);", "lang": "painless", "params": { "vs": ["a","b"] } } } } } } }
这里额外增加了空数组的判断,避免数组为空时出现索引越界错误。
内容的提问来源于stack exchange,提问作者jason135
相关产品推荐
相关产品推荐

