Elasticsearch如何通过多字段匹配规则对桶内文档进行自定义排序
问题原因
你之前的boost方案失效是因为只要显式指定了student.name作为排序字段,Elasticsearch默认会放弃_score的排序规则,所以boost的权重直接失效;而multi search的方式分页需要自己合并多个查询的结果,复杂度很高。
解决方案
你可以给四个优先级档位分配固定权重,排序时先按权重从高到低排列,同档位再按student.name排序即可,天然支持原生分页逻辑。四个档位的权重分配参考:
- 档位1(
new_student: true且total_marks > 0):4分 - 档位2(
new_student: false且total_marks > 0):3分 - 档位3(
new_student: true且total_marks = 0):2分 - 档位4(
new_student: false且total_marks = 0):1分
方案1:脚本排序(实现简单,适合中小数据量)
直接在sort参数中使用painless脚本计算每个文档的优先级分:
GET 替换为你的索引名/_search { "query": { "match_all": {} // 可替换为你的业务过滤条件 }, "sort": [ { "_script": { "type": "number", "script": { "lang": "painless", "source": """ boolean isNew = doc['student.new_student'].value; int marks = doc['student.total_marks'].value; if (isNew && marks > 0) return 4; if (!isNew && marks > 0) return 3; if (isNew && marks == 0) return 2; return 1; """ }, "order": "desc" } }, { "student.name.keyword": { // 必须使用keyword类型字段排序,不可用text类型 "order": "asc" } } ] }
方案2:function_score预计算权重(性能更高,适合大数据量)
不需要使用脚本,在查询阶段就计算好优先级权重,再按权重和姓名排序:
GET 替换为你的索引名/_search { "query": { "function_score": { "query": { "match_all": {} }, // 可替换为你的业务过滤条件 "functions": [ { "filter": { "bool": { "must": [ { "term": { "student.new_student": true } }, { "range": { "student.total_marks": { "gt": 0 } } } ] } }, "weight": 4 }, { "filter": { "bool": { "must": [ { "term": { "student.new_student": false } }, { "range": { "student.total_marks": { "gt": 0 } } } ] } }, "weight": 3 }, { "filter": { "bool": { "must": [ { "term": { "student.new_student": true } }, { "term": { "student.total_marks": 0 } } ] } }, "weight": 2 }, { "filter": { "bool": { "must": [ { "term": { "student.new_student": false } }, { "term": { "student.total_marks": 0 } } ] } }, "weight": 1 } ], "boost_mode": "replace" } }, "sort": [ { "_score": { "order": "desc" } }, { "student.name.keyword": { "order": "asc" } } ] }
注意事项
两种方案的分页逻辑和普通ES查询完全一致,直接用from+size或者search_after即可,不需要额外处理分页合并逻辑。
内容的提问来源于stack exchange,提问作者Manonandan S K
相关产品推荐
相关产品推荐

