Elasticsearch查询如何实现结果去重 每个相同条目仅返回1条
Elasticsearch 匹配结果去重实现方法
完全可以在保留全量匹配规则、prGreater字段排序逻辑的前提下实现结果去重,根据使用场景可选两种成熟方案:
方案1:字段折叠(collapse)—— 常规分页查询首选
这是改动最小、性能最优的方案,原理是按你指定的重复判定字段对结果做折叠,每个唯一字段值仅返回排序优先级最高的1条文档,完全兼容现有过滤、排序、分页逻辑。
前置要求
字段折叠仅支持精确匹配类型字段(keyword、数值、日期均可),你当前mapping中nmId、name、estdPaper为text类型,无法直接用于折叠。如果业务上判定重复的规则是nmId相同即为同一条目,需要先给nmId添加keyword子字段(无需重建全量索引,执行mapping更新即可生效):
PUT 你的索引名/_mapping { "properties": { "nmId": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }
修改后的查询
在原有查询基础上增加collapse配置即可,按nmId去重的示例如下:
{ "size": 100, "query": { "bool": { "filter": [ { "range": { "dhDay": { "from": "2022-06-23T00:00:00.000+0000", "to": "2022-06-24T13:33:04.432+0000", "include_lower": true, "include_upper": false, "boost": 1.0 } } } ], "adjust_pure_negative": true, "boost": 1.0 } }, "collapse": { "field": "nmId.keyword" // 替换为实际判定重复的精确类型字段即可 }, "sort": [ { "prGreater": { "order": "desc" } } ] }
该写法会自动保留你设置的prGreater倒序规则,每个重复值仅返回排序最靠前的1条文档,原有size、from分页参数可正常使用。
方案2:terms聚合+top_hits子聚合 —— 需要统计去重总数时使用
如果除了拉取去重后的结果,还需要获取去重后的总条目数,可以使用聚合方案:
{ "size": 0, "query": { "bool": { "filter": [ { "range": { "dhDay": { "from": "2022-06-23T00:00:00.000+0000", "to": "2022-06-24T13:33:04.432+0000", "include_lower": true, "include_upper": false, "boost": 1.0 } } } ] } }, "aggs": { "dedup_result": { "terms": { "field": "nmId.keyword", // 去重判定字段 "size": 100 // 对应原查询的返回条数 }, "aggs": { "top_item": { "top_hits": { "sort": [ { "prGreater": { "order": "desc" } } ], "size": 1 // 每个分组仅返回1条排序优先级最高的结果 } } } } } }
该方案的缺点是深度分页实现复杂、性能弱于collapse,普通列表查询优先选择方案1即可。
补充:如果返回的重复条目是文档
_id完全一致的数据,优先检查写入逻辑是否存在重复提交问题,写入端做幂等校验是根治数据重复的最优方案。
内容的提问来源于stack exchange,提问作者Henrique
相关产品推荐
相关产品推荐

