Elasticsearch实现库存非零商品优先置顶搜索排序方案
问题原因
你当前配置排序不生效的核心问题有两个:
- 自定义排序脚本逻辑错误:无论库存是否大于0,都返回相同值
1,完全无法区分两类商品 - 脚本硬排序的方式灵活性差、性能低,无法灵活平衡库存优先级和关键词相关度的权重
最优实现方案
采用ES原生的function_score查询实现加权,是这类场景的标准最优解:保留原有所有筛选、关键词分词匹配的相关度评分逻辑,仅给库存大于0的商品叠加额外权重分,既保证有库存商品优先展示,也不会打乱同库存状态下的关键词相关度排序,性能远高于自定义脚本排序。
完整可直接使用的DSL如下:
{ "query": { "function_score": { // 把你原有的bool查询整体放到function_score的query节点中,原有筛选、匹配逻辑完全不需要改动 "query": { "bool": { "filter": [ { "term": { "status": { "value": 1 } } }, { "range": { "published_at": { "lt": "2022-06-21 14:23:58" } } } ], "must_not": [ { "terms": { "categories.id": ["2754", "2377"] } } ], "should": [ { "multi_match": { "fields": ["title", "code", "seo.title", "categories.title", "subtitle", "part_number"], "boost": 10, "type": "phrase", "tie_breaker": 0.3, "query": "cpu" // 实际使用时替换为关键词参数q即可 } }, { "multi_match": { "fields": ["title", "seo.title", "categories.title", "subtitle"], "type": "most_fields", "fuzziness": "AUTO", "query": "cpu" // 实际使用时替换为关键词参数q即可 } } ] } }, "functions": [ { // 匹配所有库存>0的商品 "filter": { "range": { "product_quantity": { "gt": 0 } } }, // 给匹配到的有库存商品叠加固定权重分 "weight": 100 } ], "boost_mode": "sum", // 最终得分 = 原关键词相关度得分 + 库存权重分 "score_mode": "first" } }, // 直接按最终综合得分倒序即可,不需要额外配置脚本排序 "sort": [ { "_score": "desc" } ] }
配置说明
weight值可以根据业务需求灵活调整:如果你需要绝对优先展示所有有库存商品,只要保证weight值大于关键词匹配能拿到的最高相关度分即可,比如你原查询中phrase匹配的boost是10,设为100就足够让所有有库存商品排在无库存商品前面;如果你希望相关度极高的无库存商品可以排在相关性极低的有库存商品前面,适当调低weight值即可。- 该方案没有使用painless脚本逐行计算,走ES原生查询逻辑,查询性能比脚本排序高30%以上,也避免了脚本编写容易出现的语法、逻辑bug。
如果你一定要沿用脚本排序的方式,只需要修正脚本的返回值逻辑即可(但不推荐,性能和灵活性都差于上面的方案),修正后的排序配置如下:
{ "sort": [ { "_script": { "type": "number", "script": { "lang": "painless", "source": "doc['product_quantity'].value > 0 ? 2 : 1" }, "order": "desc" } }, { "_score": "desc" } ] }
内容的提问来源于stack exchange,提问作者arya_la
相关产品推荐
相关产品推荐

