Elasticsearch 如何实现类主流搜索引擎广告置顶显示效果?

1、需求

  • wx私信问题:Elasticsearch 如何实现类似百度广告置顶显示给定商品数据的效果?

置顶显示某特定数据就是:搜索某关键词,出现关联广告置顶显示的效果。

举例:百度搜索“电动汽车”,结果如下:

上面实现的本质:返回结果的第一页头1条或多条数据是服务端(如电商网站、主流搜索引擎)指定的数据,而非按照相关度评分计算得出的结果数据。

这时候,不禁要问 Elasticsearch 能实现类似功能不 ?

2、拆解实现

Elasticsearch from + size 分页实现机制的原理(大致意思):

  • page 1:from 0,size:10——返回第 0 到 第 9 条数据。

  • page 2:from 10,size:10——返回第 0 到 第 19 条数据,截取第 10 到 第 19 条数据;

  • page 3:from 20,size:10——返回第 0 到 第 29 条数据,截取 第 20到 第 29 条数据。

  • ……

本质 是深度分页,肯定越往后翻页响应越慢。

要实现根据固定关键词添加特定数据置顶显示的效果,探讨方案如下:

2.1 方案一:不重新分页,牺牲首页部分数据

不再做重新分页,强制将 page 1 部分数据,换成:类【广告位】置顶显示数据。

显然,会有数据丢失,导致搜索精准率下降,用户一般不会接受。

2.2 方案二:重新内存分页

将类【广告位】置顶显示数据 + 已有返回的前10页(举例:100 条数据)重新组合后,再分页。

需要内存维护一堆数据,有较大内存开销。用户期望翻页越深(比如:100页+),维护数据越大,处理越慢、延时会越明显。

2.3 方案三:其他方案

类主流搜索引擎实现的方法或者读者新的实现机制。

但,此时要想,有没有更简洁的实现呢?

Elastic 官方就没有考虑这个用户需求吗?

有的,Elasticsearch 7.4.0 新增的 pinned query 就能实现这种功能。

且听慢慢道来……

3、pinned query 介绍

pinned query 是 Elasticsearch 7.4.0 版本实现的增强检索功能。

pinned:中文翻译为“固定”。

pinned query 则可以解释为——固定某些结果首页置顶显示的检索方式。

下图更能形象的说明:绿色的 Pinned results 就是要首页置顶显示的结果。

4、 pinned query 实战实现

基础数据 Demo 如下,直接拿文章开头的截图示例模拟一下,假设 id为 1、2、3 的3条数据是需要特意置顶显示的数据。

PUT index_001 {   "mappings": {     "properties": {       "title":{         "type": "text",         "analyzer": "ik_max_word",         "fields": {           "keyword":{             "type":"keyword"           }         }       }     }   } } PUT index_001/_bulk {"index":{"_id":1}} {"title":"大众汽车首款纯电动ID.4_预售进行时_先订先享"} {"index":{"_id":2}} {"title":"保时捷首款纯电动跑车Taycan - 现已到店 - 电驰神往"} {"index":{"_id":3}} {"title":"纯电动电动汽车?英国国际贸易部_邀您来投资英国汽车工业"} {"index":{"_id":4}} {"title":"四轮电动车_ 电动汽车报价_阿里巴巴采购批发_超多品类低价批发"} {"index":{"_id":5}} {"title":"电动汽车之家,为新能源汽车而生 - 第一电动网"} {"index":{"_id":6}} {"title":"中国电动汽车网_新能源汽车_电动汽车网"} {"index":{"_id":7}} {"title":"电车之家_领先的电动汽车及新能源汽车行业门户网站"} 

如果要召回既包含:“电动汽车” 完全匹配,又包含“电动”或“汽车” 分词匹配的全量数据。 大致的检索语句如下:

POST index_001/_search {   "query": {     "bool": {       "should": [         {           "match_phrase": {             "title": {               "query": "电动汽车",               "boost": 5             }           }         },         {           "bool": {             "should": [               {                 "match": {                   "title": "电动"                 }               },               {                 "match_phrase": {                   "title": "汽车"                 }               }             ],             "minimum_should_match": 2           }         }       ]     }   } } 

如上检索部分:完 全匹配加了 boost  提升权重。

回结果如下:

返回结果按照评分由高到低顺序排列,_id 序列为:5、7、3、6、4 ……

置顶显示_id 为1、2、3的数据,pinned query 实现如下:

GET index_001/_search {   "query": {     "pinned": {       "ids": [         "1",         "2",         "3"       ],       "organic": {         "bool": {           "should": [             {               "match_phrase": {                 "title": {                   "query": "电动汽车",                   "boost": 5                 }               }             },             {               "bool": {                 "should": [                   {                     "match": {                       "title": "电动"                     }                   },                   {                     "match_phrase": {                       "title": "汽车"                     }                   }                 ],                 "minimum_should_match": 2               }             }           ]         }       }     }   } } 

本质是在原来检索语句的基础上,添加了如下部分代码:

"pinned": {      "ids": [        "1",        "2",        "3"      ],      "organic": { 

第一:置顶显示的 id ,写法如下:

  "pinned": {       "ids": [ 

第二:除了置顶数据之外的其余正常检索语句块内容。只是加了“organic” 包裹一层。其中的检索语句还是原来的写法 ,拷贝过来即可。

返回结果如下:

返回结果已 pinned(类似做了“广告位”定制), _id 序列为:1、2、3、5 ……. 实现了类百度置顶显示广告的效果。

5、 pinned query 源码解读

5.1 认知前提:源码中最大评分计算方法

float MAX_ORGANIC_SCORE = Float.intBitsToFloat((0xfe << 23)) - 1; 

本质下面代码等价:

float max_rst  = (float)Math.pow(2,127);//1.7014118E38 

也就是说:MAX_ORGANIC_SCORE 大小为:2 的 127 次幂,是 Elasticsearch float 最大值。

5.2 最大评分作用

正常查询的评分得分不会超过 MAX_ORGANIC_SCORE, 将固定查询(pinned query)的评分设定为:MAX_ORGANIC_SCORE。

5.3  pinned query 保证置顶显示解密

原理:将置顶显示的数据通过 bool 组合查询 + boost 提升权重的方式给设置了 float 最大值评分,这样就能保证置顶显示了。

核心源码实现如下:

注意细节没有深究,比如:置顶返回的结果显示的是原始评分。

6、小结

读者可能会问:这并没有实现基于特定关键词返回特定数据的需求?其实有了pinned query 再将特定关键词与待置顶显示文章 _id 建立个一对多的映射关系就可以实现。映射关系可以自己内存维护或者借助 redis 实现都可以。

你、我 发现的新需求,很可能别人早就发现,且已经提交 Git了。更可怕的是: 官方新版本已经实现了!

要注重基础夯实的同时,多关注一下技术动态。 两手抓、两手都要硬!

中国最大的 Elastic 非官方公众号

点击查看“ 阅读原文 ”,获取近10小时进阶 视频教程 ,和全球近 1000 位 Elastic 爱好者一起每日精进 ELK 技能!

铭毅天下Elasticsearch
我还没有学会写个人说明!
上一篇

美一只白尾鹿死亡并被发现患有“多毛眼球”疾病

下一篇

敏捷史话(七):从程序员、作家到摇滚乐手——Andy Hunt的多面人生

你也可能喜欢

评论已经被关闭。

插入图片