Elasticsearch使用match_phrase查询如何返回去重的tags标签数据
方案1:全局跨文档去重(直接返回所有唯一标签集合)
如果你需要获取所有匹配文档中不重复的标签列表,直接使用嵌套聚合实现,ES侧直接完成去重逻辑,查询语句如下:
{ "size": 0, // 不需要返回原始文档 "query": { "nested" : { "path" : "tags", "query" : { "bool" : { "must" : [ { "match_phrase" : {"tags.name" : "thriller"} } ] } } } }, "aggs": { "all_tags": { "nested": { "path": "tags" }, "aggs": { "unique_tags": { "terms": { "field": "tags.name.keyword", // 需确保tags.name有keyword类型子字段,若本身是keyword类型可直接写tags.name "size": 1000 // 调整这个值控制返回唯一标签的数量上限 }, "aggs": { "tag_detail": { "top_hits": { "size": 1, // 每个唯一标签只取第一条匹配的完整信息 "_source": ["tags.tag_id", "tags.name", "tags.type"] } } } } } } } }
返回结果的聚合部分会直接给出所有不重复的标签以及对应的tag_id、type信息。
方案2:单个文档内部tags去重(保留原文档返回结构)
如果你需要保留原有文档的返回结构,仅对每个文档内部的重复标签做去重,可以使用script_fields自定义返回字段,通过脚本实现数组去重:
{ "size": 20, "_source": false, // 关闭原始_source返回,用自定义字段替代 "sort": [ { "@timestamp": { "order": "desc" } } ], "query": { "nested" : { "path" : "tags", "query" : { "bool" : { "must" : [ { "match_phrase" : {"tags.name" : "thriller"} } ] } } } }, "script_fields": { "unique_tags": { "script": { "source": """ def unique = []; def seen = new HashSet(); for (tag in params._source.tags) { if (!seen.contains(tag.name)) { seen.add(tag.name); unique.add(tag); } } return unique; """, "lang": "painless" } } } }
返回结果中每个文档的unique_tags字段就是去重后的标签列表。
注意事项
- 方案1的terms聚合要求
tags.name对应字段为keyword类型,若你使用的是text类型字段,需要提前为其配置keyword子字段才能正常聚合。 - 方案2要求你的ES集群开启了painless脚本的使用权限,默认配置下该权限是开启的。
内容的提问来源于stack exchange,提问作者The Coder
相关产品推荐
相关产品推荐

