ElasticSearch按分类、变体多层分组取每组最高得分商品查询问题
ElasticSearch 多级分组取Top1实现方案
最优实现方案(推荐)
你当前的查询已经可以正确拿到每个category_id下得分最高的商品列表,由于分类数量通常不会太大,直接对聚合返回的结果在内存中做二次分组即可,开发成本极低、兼容性好、性能无额外损耗:
- 解析你现有查询返回的
category_id_max_product聚合结果,提取所有分类Top1商品的id、variant_id、_score字段 - 在业务代码中按
variant_id对上述商品列表分组,每个分组保留_score最高的1个商品即可得到最终结果
单ES查询实现方案(仅作参考)
如果你需要通过单次ES查询直接得到最终结果,可以使用scripted_metric自定义聚合逻辑实现,兼容所有ES 7.x版本,查询语句如下:
{ "query": { "function_score": { "functions": [ { "field_value_factor": { "field": "item_id", "factor": 0 } }, { "filter": { "term": { "id": "PRODUCT_46831" } }, "weight": 1 }, { "filter": { "term": { "id": "PRODUCT_47139" } }, "weight": 0.95 }, { "filter": { "term": { "id": "PRODUCT_46833" } }, "weight": 0.9 }, { "filter": { "term": { "id": "PRODUCT_46834" } }, "weight": 0.85 }, { "filter": { "term": { "id": "PRODUCT_46835" } }, "weight": 0.8 } ], "score_mode": "sum", "boost_mode": "sum", "query": { "bool": { "must": [ { "terms": { "id": [ "PRODUCT_46831", "PRODUCT_47139", "PRODUCT_46833", "PRODUCT_46834", "PRODUCT_46835" ], "boost": 0 } } ] } } } }, "aggs": { "final_result": { "scripted_metric": { "init_script": "state.category_top = [:]; state.variant_top = [:]", "map_script": """ def cid = doc['category_id'].value; def score = _score; if (!state.category_top.containsKey(cid) || score > state.category_top[cid].score) { state.category_top[cid] = [ 'id': doc['id'].value, 'variant_id': doc['variant_id'].value, 'score': score ]; } """, "combine_script": """ def category_list = state.category_top.values(); def variant_top = [:]; for (item in category_list) { def vid = item.variant_id; if (!variant_top.containsKey(vid) || item.score > variant_top[vid].score) { variant_top[vid] = item; } } return variant_top.values(); """, "reduce_script": """ def all_variant_items = []; for (shard_result in states) { all_variant_items.addAll(shard_result); } def final_variant_top = [:]; for (item in all_variant_items) { def vid = item.variant_id; if (!final_variant_top.containsKey(vid) || item.score > final_variant_top[vid].score) { final_variant_top[vid] = item; } } return final_variant_top.values(); """ } } }, "size": 0 }
查询说明
自定义聚合逻辑完全对齐你的需求:
- map阶段:每个分片内先按category_id分组,保留每个分类得分最高的商品
- combine阶段:每个分片内对分类Top1结果按variant_id分组,保留每个变体得分最高的商品
- reduce阶段:合并所有分片的结果,再次按variant_id去重取Top1得到最终结果
内容的提问来源于stack exchange,提问作者dilkash
相关产品推荐
相关产品推荐

