Elasticsearch聚合分桶后如何按_score阈值过滤结果
解决方案
ES 7.17 中管道聚合(比如Bucket Selector)确实无法直接引用_score元字段,有两种可落地的实现方式,都支持按分桶最高得分过滤结果:
方案1:ES聚合侧原生过滤(无需业务侧后处理)
核心思路是先通过max指标聚合把每个uid分桶的最高_score提取为可被管道聚合引用的指标,再通过Bucket Selector按阈值过滤分桶,同时调整terms聚合的排序规则匹配按得分降序的需求。
注意:必须调整
rescore.window_size参数,默认值100表示仅对query阶段返回的前100条文档做重算分,如果总命中文档数超过这个值,未进入窗口的文档会保留原始match查询的分数,导致聚合结果错误,需要把该值设为大于等于query总命中数。
修改后的查询示例(阈值设为0.98):
{ "size": 0, "query": { "match": { "person": "John Smith" } }, "rescore": { "window_size": 1000, "query": { "rescore_query": { "function_score": { "pair_score": { "field": "person", "query_name": { "data": "John Smith" } } } }, "query_weight": 0.0, "rescore_query_weight": 1.0 } }, "aggs": { "top-uids": { "terms": { "field": "uid", "order": { "max_bucket_score": "desc" }, "size": 10000 }, "aggs": { "max_bucket_score": { "max": { "script": "_score" } }, "top_uids_hits": { "top_hits": { "sort": [ { "_score": { "order": "desc" } } ], "size": 1 } }, "score_filter": { "bucket_selector": { "buckets_path": { "topScore": "max_bucket_score" }, "script": "params.topScore > 0.98" } } } } } }
参数说明:
rescore.window_size:根据实际业务命中量调整,确保所有匹配文档都经过重算分terms.size:设置为需要返回的最大uid分桶数,默认值10会导致低分桶被过滤后返回结果不足bucket_selector.script:替换为实际需要的分数阈值即可
方案2:业务侧轻量后处理
如果不想改动现有查询逻辑,由于查询设置了size:0,仅返回聚合结果,数据量极小,可以直接在业务代码层做过滤:遍历返回结果中aggregations.top-uids.buckets数组,保留top_uids_hits.hits.hits[0]._score(或top_uids_hits.hits.max_score)大于阈值的分桶即可,实现成本极低,性能开销可以忽略。
两种方案都能满足需求,前者直接在ES侧返回最终结果,后者无需调整现有查询配置,可根据实际场景选择。
内容的提问来源于stack exchange,提问作者Stpete111
相关产品推荐
相关产品推荐

