1、需求wx私信问题: Elasticsearch如何实现在百度广告顶端显示特定商品数据的效果?
将某个特定数据显示在上面是指出现检索某个关键词并显示在相关广告上面的效果。
例如,在百度上搜索“电动汽车”,结果如下。
上述实现的本质:结果的第一页的第一个或多个数据是服务器(例如,电子商务网站、主要搜索引擎)指定的数据,而不是基于关联度得分计算的结果数据。
此时,不得不问,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方案2 )内存分页类【广告位】开头返回数据的前10页(例如: 100条数据)重新组合后分页。
内存需要维护大量数据,内存开销很大。 用户将页面翻得越深,例如100页,维护数据越大,处理越慢,延迟越明显。
2.3方案3 :其他方案类主流搜索引擎实现的方法或读者新的实现机制。
但是,这个时候,有没有实现得更简洁一些?
Elastic没有正式考虑这个用户需求吗?
是的,Elasticsearch 7.4.0中新增的pinned query可以实现此功能。
请慢慢听……。
3、pinned query介绍pinned query是elastic search7.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 ' : ' ' fields ' : { ' keyword ' : { ' type ' : ' keyword ' } } put index _ 001/_ bulk { ' Inde }
{"_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了。更可怕的是:官方新版本已经实现了!
要注重基础夯实的同时,多关注一下技术动态。两手抓、两手都要硬!
参考:
https://www.elastic.co/guide/en/elasticsearch/reference/7.4/release-notes-7.4.0.html
推荐:
全网首发!《 Elasticsearch 最少必要知识教程 V1.0 》低调发布
从实战中来,到实战中去——Elasticsearch 技能更快提升方法论
你的 Elasticsearch 难题,官方文档早就有了答案......
从提高 Elasticsearch 搜索体验说开去......
中国最大的 Elastic 非官方公众号
点击查看“阅读原文”,获取近10小时进阶视频教程,和全球近 1000 位 Elastic 爱好者一起每日精进 ELK 技能!