Elasticsearch 如何實現相似推薦功能?
1、什麼是相似推薦?
拿我們身邊的算法 “投餵” 爲主的頭條、抖音、微信視頻號等舉例,如果你喜歡乒乓球,每天推送給你的都是乒乓球比賽視頻集錦;如果你喜歡成功人士演講,每天都是馬雲、馬化騰、劉強東等商業巨鱷的演講。
再拿電商的示例如下:比如我近期購買的吳軍老師推薦的科普經典鉅著《從一到無窮大》,京東會給我推薦樊登讀書帶火的書《微積分原理》。
其實,在實際業務實戰環節,或多或少也會有類似的功能,Elasticsearch 有沒有類似功能呢?
大家實戰環節遇到的問題也大致如下:
Q1:ES 有相似搜索這個功能吧?我記得有個 suggester 吧?
Q2:ES 有沒有處理相似文字的案例?把相似文章聚合起來。
來自《死磕 Elasticsearch 知識星球》微信羣
2、Elasticsearch 相似推薦功能實現
這裏不得不介紹:MLT 檢索。對!你沒看錯。不是:MIT(麻省理工學院),是 Elasticsearch 一種檢索類型 MLT(More Like This Query )。
看下圖,建立個全局認識。MLT 屬於:Query DSL 下的專業檢索(Specialized queries)的範疇。
3、More Like This 檢索介紹
More Like This 檢索定義:查找與給定文檔 “相似” 的文檔。
4、More Like This 底層邏輯
MLT 查詢簡單地從輸入的待查詢文本中提取文本,對其進行分析,通常在字段中使用相同的分析器,然後選擇具有最高 tf-idf 的前 K 個詞組以形成這些詞組的組合查詢語句。
假設我們想找到與給定輸入文檔相似的所有文檔。顯然,輸入文檔本身應該是該類型查詢的最佳匹配。爲什麼呢?基於 Lucene tf-idf 評分公式計算得出的呀。
如下就是 Lucene tf-idf 評分模型。
如果對此評分不瞭解的同學,推薦閱讀:
乾貨 | 一步步拆解 Elasticsearch BM25 模型評分細節
實戰 | Elasticsearch 自定義評分的 N 種方法
MLT 查詢的本質是:從待檢索語句中提取文本,然後用分詞器切分,選擇 tf-idf 分值高的前 K 個術語形成檢索語句。基於檢索語句返回的結果就是相似度查詢結果。
爲避免歧義,對照的英文如下:
The MLT query simply extracts the text from the input document, analyzes it, usually using the same analyzer at the field, then selects the top K terms with highest tf-idf to form a disjunctive query of these terms.
如果原理還不夠清晰,我將核心 Lucene 源碼的邏輯簡要說明如下:
- 步驟 1:根據輸入的待查詢的文檔,抽取詞組單元(term),結合 TF*IDF 評分形成優先級隊列。
抽取詞時會過濾掉停用詞、不滿足最小詞頻的詞等不滿足限定條件的詞。
- 步驟 2:結合步驟 1 的優先級隊列,生成布爾查詢語句。
Lucene 源碼部分截圖
循環超過最大查詢詞數目,則停止構建查詢語句。
最大查詢數據值 max_query_terms 默認是:25。增加此值會以犧牲查詢執行速度爲代價提供更高的準確性。
- 步驟 3:基於步驟 2 構造的布爾查詢語句,獲取查詢結果。
返回結果就是類似推薦功能的相似文章。
看的出來,這比我們常見的精準匹配 term query 和全文檢索 match query、match_pharse query 都要複雜很多。
5、More Like This 前置條件
執行 MLT 的字段必須被索引並且類型爲 text 或 keyword。此外,當對文檔使用相似度檢索時,必須啓用 _source 或設置爲 stored 或存儲爲 term_vector。爲了加快分析速度,可以在索引時存儲 terrm vectors。
讀者看到這裏可能會疑惑:啥叫 term vectors ?
有必要解釋一下:
term vectors 組成:
-
terms 分詞單元列表。
-
每個分詞單元的位置 position 和序號。
-
分詞後的單詞或字在原有串中的起始位置 start_offset 、結束位置 end_offset 和偏移值。
-
有效載荷。與位置相關的用戶定義的二進制值。
給了一堆術語,還是看不懂,再來?!
給個例子,一看就明白了。
PUT my-index-0000012
{
"mappings": {
"properties": {
"text": {
"type": "text",
"term_vector": "with_positions_offsets"
}
}
}
}
PUT my-index-0000012/_doc/1
{
"text": "Quick brown fox fox"
}
GET /my-index-0000012/_termvectors/1
position 更精確的說法是:序號。
-
Quick 的 position 爲 0;
-
brown 的 position 爲 1;
-
quick 的 start_offset 爲 0;
-
quick 的 end_offset 爲 5。
6、More Like This 實戰一把
光說不練是假把式,實戰一把,一探究竟。
插入一批數據,數據來源:百度熱點新聞 。
DELETE news
PUT news
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
POST news/_bulk
{ "index": { "_id":1 }}
{"title":"演唱會突發意外!知名男星受傷,本人最新迴應"}
{ "index": { "_id":2 }}
{"title":"張傑演唱會主辦方道歉:舞臺升降設備出現故障"}
{ "index": { "_id":3 }}
{"title":"謝娜發文迴應張傑受傷"}
{ "index": { "_id":4 }}
{"title":"張傑迴應受傷:不會有大礙,請歌迷和家人朋友們放寬心"}
{ "index": { "_id":5 }}
{"title":"張傑表演時從電梯墜落 手指血流不止"}
{ "index": { "_id":6 }}
{"title":"謝娜迴應張傑受傷:他問的第一句話就是怕嚇到女兒"}
{ "index": { "_id":7 }}
{"title":"張傑演唱會出意外後,髮長文給粉絲報平安,謝娜透露張傑本人..."}
{ "index": { "_id":8}}
{"title":"張傑明星資料大全愛奇藝泡泡"}
PS:以上僅是百度公開的熱點新聞,以此舉例相似查詢,別無其他用途,特此說明。
執行 MLT:
POST news/_search
{
"query": {
"more_like_this": {
"fields": [
"title"
],
"like": [
"張傑開演唱會從升降機上掉落"
],
"analyzer": "ik_smart",
"min_doc_freq": 2,
"min_term_freq": 1
}
}
}
返回結果如下:
以如上截圖最後一條數據爲例,強調說明一下:注意到一個細節,返回結果只是相似,並沒有真正做到語義相關。
7、More Like This 核心語法詳解
參數看着很好解釋,但着實非常難理解,特此解讀如下:
- "min_doc_freq": 2
最小的文檔頻率,默認爲 5。
什麼意思呢?
就拿上面的示例來說,至少得有兩篇文章纔可以,不管這兩篇文章與輸入相關與否。
更具體點說,如果 bulk 寫入僅一篇 document,哪怕和標題一致也無法返回結果。
- "min_term_freq": 1
文檔中詞組的最低頻率,默認是 2,低於此頻率的會被忽略。
什麼意思呢?
就是待檢索語句的其中一個分詞單元的詞頻的最小值。
PUT news
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
POST news/_bulk
{ "index": { "_id":1 }}
{"title":"張傑演唱會突發意外!知名男星受傷,本人最新迴應"}
{ "index": { "_id":2 }}
{"title":"hello kitty"}
POST news/_search
{
"query": {
"more_like_this": {
"fields": [
"title"
],
"like": [
"張傑迴應張傑受傷"
],
"analyzer": "ik_smart",
"min_doc_freq": 1,
"min_term_freq": 2
}
}
}
上面的例子更有說服力。
更爲具體的說,like 部分待檢索語句的分詞詞頻要至少有一個 >=2 。
更多參數建議參考官方文檔,不再贅述。
8、Elasticsearch 相似推薦其他的實現方案
在第 6 部分提及,more like this 並沒有實現完全的相關度推薦,出現了 “噪音” 數據。
所以,實戰環節使用 more like this 多半基於燃眉之急。
如果想深入的實現相似度推薦,推薦方案:
基於類似 simhash 的方式,給每個文檔打上 hash 值,基於海明距離實現相似度推薦。
如果想再深入就需要藉助:
基於協同過濾的推薦算法、基於關聯規則的推薦算法、基於知識的推理算法或者組合推理算法實現。
9、小結
本文介紹了 Elasticsearch 中實現相似推薦的 More Like This 檢索方法、實現原理、案例解讀。
目的是給大家業務系統實現相似推薦提供了理論和實踐支撐。
大家實戰環節如何實現的相似推薦呢?歡迎留言討論細節。
參考
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
https://spoon-elastic.com/all-elastic-search-post/more-like-this-query-mlt-suggest-similar-content-with-elasticsearch/
https://qbox.io/blog/mlt-similar-documents-in-elasticsearch-more-like-this-query/
https://spoon-elastic.com/all-elastic-search-post/more-like-this-query-mlt-suggest-similar-content-with-elasticsearch/
https://newbedev.com/elasticsearch-more-like-this-query
https://www.linkedin.com/pulse/finding-similar-documents-elasticsearch-morelikethis-fl%C3%A1vio-knob?articleId=6657988773374111744
《Lucene 原理與代碼分析》
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/apPGngRQx6bJEmR82XlXhQ