当前位置: 首页 > news >正文

es修改排序_ElasticSearch 评分排序

背景

通过脚本改变评分

背景

近期有一个需求,需要对优惠券可用商品列表加个排序,只针对面值类的券不包括折扣券。

需求是这样的,假设有一张面值券 50 块钱,可用商品列表 A 100、B 40、C 10,当用户查询当前券可用商品列表的时候优先将卡券可以直接抵扣且不需要用户在额外支付的商品排在前面。

C 10

B 40

A 100

其实排序有很多侧重,比如:

1.根据用户利益最大化原则,排序列表应该是 B、C、A

2.根据用户购买习惯,有可能是 A、B、C

3.根据运营策略、第三方利益等有可能是C、B、A

这里暂且先不扩展如何对商品列表进行智能排序,如果需要完整的个性化商品推荐,涉及很多东西,后面有经验在拿来分享。

我们就这个简单的 case,一开始最直接的想法就是加个排序列,建索引的时候将排序值计算好直接写入。后来分析了下原来索引(index) 结构不是这种笛卡尔积的排列,所以在短时间内很难立马上线,需要新建 index 结构。

后来通过讨论用影响评分的方法来解决,可以节省时间快速上线。

通过脚本改变评分

ES query DSL 支持很多种类型的查询,结果的排序如果没有特殊声明 sort field 则是根据es打分(score)来排序的,score 分值越高排序越靠前。

ES score 计算比较复杂,涉及到 TF(词频)/IDF(逆向文档频率)、罕见词、匹配文档长度、权重 boost 向量空间模型 等,不过 ES 提供了几种封装好的评分插件供使用。

function_score 查询来让我们根据业务场景改变文档评分方法,根据业务场景我们需要完全控制 score 生成的逻辑,所以我们选择 script_score 方式。

脚本默认是 groovy,当然也可以根据需要使用其他脚本语言,我们来看下实现。

script.inline: on

script.enfine.groovy.inline.aggs: on

script.indexed: on

script.file: on

首先在 es.yml 配置中打开脚本支持相关选项。

{

"query": {

"function_score": {

"query": {

"bool": {

"should": [

{

"match": {

"productName": "英语"

}

}

]

}

},

"score_mode": "first",

"script_score": {

"lang": "groovy",

"params": {

"couponPrice": 100

},

"script": "def deduct = couponPrice - doc['unitCost'].value.toFloat(); if (deduct > 0) {return 10000 + deduct;}else if(deduct==0 || (deduct<1 && deduct>0)){return 20000;}else{return doc['unitCost'].value.toFloat()-couponPrice;}"

},

"boost_mode": "replace"

}

},

"from": 0,

"size": 100

}

查询条件可以任意,关键是 script_score 对象,script 是需要 ES 脚本引擎执行的脚本代码。

一个比较重要的选项 boost_mode ,boost_mode 是控制整个 document 的评分方式,这里我们选择替代(replace)默认计算好的评分。

这里面的排序有一个小技巧,如何将负数排序在前面,正数排序在后面,还有抵扣后是0的处理。

def deduct = couponPrice - doc['unitCost'].value.toFloat();

if (deduct > 0) {

return 10000 + deduct;

}else if(deduct==0 || (deduct<1 && deduct>0)){

return 20000;

}else{

return doc['unitCost'].value.toFloat()-couponPrice;

}

通过 couponPrice 变量表示优惠券面值金额,如果当前商品抵扣完是负数说明需要排序在前面,那么如何和抵扣完正数分开尼,这里可以取一个稍微大点的值加上抵扣后的负值,这样把负值转换成正数自然就排序在前面。

抵扣后等于0的或者小于1大于0的值也是可以优先安排在前面,当然这里还是不够灵活的,最好的方式是根据当前面值、商品价格动态计算才准确。

最后就是抵扣完需要用户在额外支付的排在最后面,直接取需要额外支付的金额数值作为排序。

通过 ES 评分我们能做很多事情,这个case只是一个简单的场景。

作者:王清培 (沪江集团资深架构师)


http://www.taodudu.cc/news/show-4919096.html

相关文章:

  • 微信小程序 17:小程序使用 npm 包和组件应用
  • 基于单片机的宠物智能投喂系统研究
  • 文件上传
  • 初识指针(3)<C语言>
  • ansible------inventory 主机清单
  • java项目之校园失物招领系统(springboot+vue+mysql)
  • 2021/06/29计算机视觉期末复习笔记整理
  • 简答题文本自动评分
  • 五角星动态评分效果
  • 微信小游戏云开发数据库
  • mysql 游戏服务器设计_网络游戏服务器数据库设计和实现.doc
  • unity数据库
  • 怎样修改游戏服务器里的数据库,修改游戏服务器中的数据库
  • echart地图修改label标签位置
  • react中label标签关联的用法
  • html中调整lable位置右移,[转载]label标签右对齐
  • label标签和input标签之间的关系
  • java label 标签_Java标签(Label)
  • CSS3学习笔记(九)——UI元素状态伪类选择器 :checked
  • 学生专用计算机如何打游戏,学生党电脑差怎么办?推荐几款低配的联机游戏,渣机也畅玩!...
  • 心理测试小游戏
  • java游戏解救人质_抖音解救人质的游戏
  • 枪战游戏html源码,html5西部牛仔枪战游戏源码
  • 使用Dart/Flutter语言开发的命令行文字RPG类型小游戏
  • 以电影为题材好玩的游戏总结
  • 基于Centos7.X的CS:GO社区服搭建
  • CS:GO 设置和优化
  • 安利一个好玩的JS编程游戏—warriorjs
  • CS和CSS的区别【吐血整理,疯狂推荐】
  • 2008游戏服务器系统下,Linux系统下玩经典游戏 CS1.5服务器架设
  • linux 搭建游戏服务器,Linux系统下玩经典游戏 CS1.5服务器架设
  • 通过「解救人质」小游戏教你学会碰撞检测
  • cocos creator实例--CocosCreator实现的 解救人质 游戏,学会碰撞检测
  • 解救人质的android游戏,一枪制敌解救人质游戏
  • mapreduce php,php mapreduce
  • hadoopStreamming 编程