Elasticsearch聚合分页使用partition参数时排序失效问题咨询
问题原因
你遇到的排序失效问题是terms聚合partition参数的固有特性导致的:partition的分片逻辑是先对所有CONTACT_ID的哈希值取模分配到对应分片,再对单个分片内的结果做排序,不是基于全局排序后的结果做分片,所以自然会出现高值CONTACT_ID被分配到后续分片、打乱全局排序的情况。
解决方案
方案1:数值类型CONTACT_ID用范围过滤分页(性能最优)
如果你的CONTACT_ID是数值类型,推荐直接在查询层加范围过滤实现全局排序分页,不需要用partition参数:
- 首次查询时不设置CONTACT_ID范围,terms聚合size设置为你单页需要的条数(比如1000),拿到当前页最后一条的CONTACT_ID作为下一页的游标
- 后续每次查询都增加range查询条件,指定CONTACT_ID < 上一页返回的最小CONTACT_ID(因为你是降序排序),就能保证每次返回的都是全局排序后下一批的结果
示例请求代码:
{ "size": 0, "query": { "range": { "CONTACT_ID": { "lt": 367884008 // 上一页返回的最后一个CONTACT_ID,首次查询可以去掉这个条件 } } }, "aggregations": { "CONTACT_ID": { "terms": { "field": "CONTACT_ID", "size": 1000, "order": { "_key": "desc" } }, "aggregations": { "DOCUMENTS": { "top_hits": { "from": 0, "size": 1, "sort": [ { "_id": { "order": "desc" } } ] } } } } } }
方案2:通用场景用composite聚合分页
如果CONTACT_ID是字符串类型,或者你不想维护范围条件,可以直接用Elasticsearch原生支持排序分页的composite聚合,该聚合会先对所有CONTACT_ID做全局排序后再分页,完全避免分片打乱排序的问题,用after参数实现翻页:
示例请求代码:
{ "size": 0, "aggregations": { "CONTACT_ID_PAGINATION": { "composite": { "size": 1000, "sources": [ { "CONTACT_ID": { "terms": { "field": "CONTACT_ID", "order": "desc" } } } ] // 首次查询不需要加after参数,后续翻页把上一次返回的after_key值填到这里 // "after": { "CONTACT_ID": 367884008 } }, "aggregations": { "DOCUMENTS": { "top_hits": { "size": 1, "sort": [ { "_id": { "order": "desc" } } ] } } } } } }
每次请求返回结果的最底部会携带after_key字段,把该字段的值填入下一次请求的after参数中即可拿到下一页的结果,所有结果天然按CONTACT_ID降序全局排序。
内容的提问来源于stack exchange,提问作者Mahdi Mohammadizadeh
相关产品推荐
相关产品推荐

