Elasticsearch按数组含指定值的脚本排序实现
Elasticsearch 自定义数组匹配排序实现
需求说明
现有文档的基础结构如下,每条文档包含categories数字数组字段:
[ { "id": 123, "name": "Ram", "status": 1, "activity": "Poster Design", "categories": [1, 2, 3, 4, 5] }, { "id": 124, "name": "Leo", "categories": [5], "status": 1, "activity": "Brochure" }, { "id": 126, "name": "Leo", "categories": [3], "status": 1, "activity": "Brochure" }, { "id": 134, "name": "Levin", "categories": [1], "status": 1, "activity": "3D Printing" } ]
需要实现的排序逻辑:
- 动态指定任意目标值(如1、3、5等)
- 所有
categories数组包含该目标值的文档,排在不包含该值的文档之前 - 同组内可自定义次级排序规则,例如指定目标值为3时,预期输出顺序为id123 → id126 → id124 → id134
实现方案
使用Elasticsearch的script sort能力实现,核心逻辑是为匹配/不匹配目标值的文档返回不同的排序权重,利用默认升序规则让权重值更小的匹配文档排在前面。
完整查询DSL如下:
GET your_index/_search { "query": { "match_all": {} // 替换为实际业务的查询过滤条件 }, "sort": [ { "_script": { "type": "number", "order": "asc", "script": { "lang": "painless", "params": { "target_val": 3 // 动态传入的目标值,修改该参数即可适配不同排序场景,无需调整脚本本身 }, "source": """ def categories = doc['categories']; // 数组包含目标值的返回低权重,不包含的返回高权重 return categories.contains(params.target_val) ? 0 : 1 """ } } }, { "id": "asc" // 同分组内的次级排序规则,可替换为name、create_time等任意业务字段 } ] }
方案说明
- 脚本复用:所有动态参数都放到
params节点传入,Elasticsearch会自动缓存编译后的脚本,不会因为频繁修改目标值产生重复编译的性能开销 - 字段要求:
categories字段需配置为数值型或keyword类型,不能是text分词类型,否则通过doc['categories']取数时会出现匹配偏差 - 灵活调整:如果需要不匹配的文档排在前面,只需将脚本里的返回值对调,或者把脚本排序的
order改为desc即可 - 性能参考:当索引数据量超过千万级时,可配合
terms查询先做粗粒度过滤,减少脚本计算的文档范围,进一步降低延迟
内容的提问来源于stack exchange,提问作者sagar43
相关产品推荐
相关产品推荐

