天天看點

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊
https://developer.aliyun.com/topic/download?id=1295 · 更多精彩内容,請下載下傳閱讀全本《Elastic Stack實戰手冊》 https://developer.aliyun.com/topic/download?id=1295 https://developer.aliyun.com/topic/es100 · 加入創作人行列,一起交流碰撞,參與技術圈年度盛事吧 https://developer.aliyun.com/topic/es100

創作人:銘毅天下

審稿人:李捷

本應用實踐,主要針對 Elasticsearch 如何實作類似百度廣告置頂顯示,給定商品資料的效果展開介紹,例如實作置頂顯示某特定資料,像搜尋某關鍵詞,出現關聯廣告置頂顯示的效果。

舉例:某搜尋引擎 “電動汽車”,結果如下:

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

上面實作的本質:

傳回結果的第一頁頭1條或多條資料是服務端(如電商網站、主流搜尋引擎)指定的資料,而非按照相關度評分計算得出的結果資料。

這時候,不禁要問 Elasticsearch 能實作類似功能不 ?

拆解實作

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 條資料。

......

本質是深度分頁,肯定越往後翻頁響應越慢。

要實作根據固定關鍵詞,添加特定資料置頂顯示的效果,探讨方案如下:

方案一:不重新分頁,犧牲首頁部分資料

不再做重新分頁,強制将 page 1 部分資料,換成:類【廣告位】置頂顯示資料。

顯然,會有資料丢失,導緻搜尋精準率下降,使用者一般不會接受。

方案二:重新記憶體分頁

将類【廣告位】置頂顯示資料 + 已有傳回的前 10 頁(舉例:100 條資料)重新組合後,再分頁。

需要記憶體維護一堆資料,有較大記憶體開銷。使用者期望翻頁越深(比如:100頁+),維護資料越大,處理越慢、延時會越明顯。

方案三:其他方案

類主流搜尋引擎實作的方法或者新的實作機制。

但此時要想,有沒有更簡潔的實作方式呢?

Elastic 官方沒有考慮這個使用者需求嗎?

有的,從 Elasticsearch 7.4.0 新增的 pinned query 就能實作這種功能。

Pinned query 介紹

Pinned query 是 Elasticsearch 7.4.0 版本之後,實作的增強檢索功能。

Pinned:中文翻譯為“固定”。

Pinned query 則可以解釋為——固定某些結果,首頁置頂顯示的檢索方式。

下圖能形象的說明:綠色的 Pinned results 就是要首頁置頂顯示的結果。

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

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 提升權重。

傳回結果如下:

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

傳回結果按照評分由高到低順序排列,_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 ,寫法如下:

第二:除了置頂資料之外的其餘正常檢索語句塊内容。隻是加了“organic” 包裹一層。其中的檢索語句還是原來的寫法 ,拷貝過來即可。

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

傳回結果已 pinned(類似做了“廣告位”定制),_id 序列為:1、2、3、5 ....... 實作了類百度置頂顯示廣告的效果。

Pinned query 源碼解讀

認知前提:源碼中最大評分計算方法

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 最大值。

最大評分作用

正常查詢的評分得分不會超過 MAX_ORGANIC_SCORE, 将固定查詢(pinned query)的評分設定為:MAX_ORGANIC_SCORE。

pinned query 保證置頂顯示解密

原理:将置頂顯示的資料通過 bool 組合查詢 + boost 提升權重的方式給設定了 float 最大值評分,這樣就能保證置頂顯示了。

核心源碼實作如下:

實作主流搜尋引擎廣告置頂顯示效果— Elastic Stack 實戰手冊

注意細節沒有深究,比如:置頂傳回的結果顯示的是原始評分。

小結

讀者可能會問:這并沒有實作基于特定關鍵詞傳回特定資料的需求?其實有了pinned query 再将特定關鍵詞與待置頂顯示文章 _id ,建立個一對多的映射關系就可以實作。映射關系可以自己記憶體維護或者借助 redis 實作都可以。

你我發現的新需求,很可能别人早就發現,且已經送出 Git了。更可怕的是:官方新版本已經實作了!

要注重基礎夯實的同時,多關注一下技術動态。兩手抓、兩手都要硬!

參考:

創作人簡介:

銘毅天下,Elastic 認證工程師、Elastic 官方合作教育訓練講師、阿裡雲 MVP、CSDN 部落格

專家、銘毅天下 Elasticsearch 公衆号作者、死磕 Elasticsearch 知識星球星主。近 10

年工作經驗,關注 Elastic Stack 技術棧、大資料技術領域。

部落格:

https://elastic.blog.csdn.net/