OpenSearch避坑指南(三)分段排序

988 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

前言

前两章,我们着重讨论了搜索召回的相关问题。一个搜索功能做的好与坏,主要取决于搜索结果的召回以及对搜索结果的排序,一个关注的是能不能搜到,一个关注的是搜索效果的好与坏。用户越想搜索的结果越在前面,则你的搜索效果越好。通常我们都是按搜索结果与搜索词的关联度来排序,往往效果也是不错了。但是在实际业务应用中,影响结果排序通常会有多个字段决定。举个例子

案例

产品有在售和停售状态(字段=isdiscontinued),为了展示结果的多样性,需要展示停售的产品。但为了不影响在售产品,需要把停售产品展示在在售产品之后,也就是分段排序。

分析

通常我们在做分段排序需求的时候,常规做法是分开去搜索。先搜出在售产品然后排序,之后再去搜索停售产品再排序。随之而来的问题有
1、排序功能与代码耦合度高,难以理解。
2、调试困难,排序的优化往往是要慢慢且多次去调整。

方案

利用opensearch的精排序的表达式来实现。先来了解一下精排序。
业务排序表达式,主要是对基础排序后召回的结果做进一步排序算分,最终返回最优结果给用户。业务排序表达式允许用户为应用自定义搜索结果排序方式,通过在查询请求中指定表达式来对结果排序。排序表达式支持基本运算(算术运算、关系运算、逻辑运算、位运算、条件运算)、数学函数和排序特征(feature)等。OpenSearch对于几种经典的应用(如论坛、资讯等)提供了表达式模板,用户可根据自己数据的特点,选择合适的表达式模板,并以此为基础进行修改,生成自己的表达式。

实现

-normalize(displayallorder)- (isdiscontinued in (2))
normalize :归一化函数,根据不同的算分将数值归一化至[0, 1]
i in (value1, value2, …, valuen) 如果i的值在集合[value1, value2, …,valuen]中出现,则该表达式值为1,否则为0。 image.png

解析

displayallorder是综合排序值,把综合排序值归一化到【0,1】之后去负值,既是倒叙排序了。怎么实现先在售产品后停售?通过(isdiscontinued in (2))来实现,这个函数计算后,在售的是0,停售的是1。这样在售的是在【0,-1】之间,停售的在【-1,-2】之间。通过数值来区分,在售产品的数值永远比停售的大。

总结

这里的案例只是对精排序的一次小试牛刀,只实现了分段排序的功能。opensearch的精排序还有很多丰富的表达式函数库,比如地区,相关性,人气模型等等。也支持AB测试。极大的方便了调试排序效果的过程。尽管elasticsearch也支持类似的功能,比如script脚本自定义score。但是要设置elasticsearch服务配置(不安全),还需要重启,每次修改脚本都是对elasticsearch的一次大手术。