Elasticsearch 8.X:這個複雜的檢索需求如何實現?
來源:銘毅天下Elasticsearch
1、企業級真實問題
問題描述如下:
如上圖所示,index中有這樣四個欄位:title content question answer。要查詢這四個欄位,支援最多輸入5個關鍵詞模糊查詢,多關鍵詞以空格隔開。
匹配度計算邏輯:
關鍵詞有序排列 ,權重依次降低,即排列在前的關鍵詞權重最高,依此降低;檢索順序和結果順序一致的排在前面。 title(question)較content(answer)權重高,比如權重高10倍 詞頻(關鍵詞出現次數)越高,匹配度越高 在匹配度相同的條件下按更新時間倒序排列
就拿上面的截圖來看,doc標題:“小學語文週週學和基礎天天練是否為配套練習?”這個doc應該排在第一位。
提問球友的 DSL 為:
{
"bool": {
"should": [
{
"multi_match": {
"query": "小學 天天 練習",
"fields": [title content question answer],
"type": "best_fields",
"tie_breaker": 0.3
}
},
{
"match": {
"title": {
"query": "小學 天天 練習",
"boost": 10
}
}
},
{
"match": {
"question": {
"query": "小學 天天 練習",
"boost": 10
}
}
}
]
}
}
2、需求重新梳理
問題有點長,我們重新梳理一下。
需求 1:檢索順序和結果順序一致的排在前面。 需求 2:title(question)較content(answer)權重高,比如權重高10倍。 需求 3:詞頻(關鍵詞出現次數)越高,匹配度越高。 需求 4:時間倒序排序。
已和提問確認,就是上述四個需求。
3、實現討論
針對需求 2,這個設定權重就可以實現。
針對需求 3,這個 TF-IDF 機制決定的,檢索後結果自然滿足,也就是評分邏輯就是基於這個實現的(後續升級為BM25模型,原理一致),我們們不用動就可以。
針對需求 4,加個時間排序就可以。
針對需求2、3、4,實現參考如下(欄位權重根據實際業務場景自我調整即可):
POST new_index_2023/_search
{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "小學 天天",
"fields": [
"title^10",
"question^10",
"content",
"answer"
],
"type": "best_fields"
}
}
]
}
},
"sort": [
{
"timestamp": {
"order": "desc"
}
}
]
}
問題來了,需求 1 :檢索順序和結果順序一致的排在前面咋搞呢?
我第一反應想到的是 Match_phrase 和 slop 結合的方案。
擴充套件說明一下:在 Elasticsearch 中,match_phrase 查詢用於搜尋精確的短語,而 slop 引數定義了詞條之間的允許的最大距離。
slop 的意思是允許搜尋的短語中的詞條有多少的移動量來使其與文件中的短語匹配。
一句話:Match_phrase 和 slop 結合的方案,並不能直接實現需求1。
那怎麼辦?我們單獨分析一下吧。
4、需求 1 實現討論
針對需求1,通常在 Elasticsearch 裡,檢索順序和結果順序一致的功能是相對複雜的,尤其是當查詢涉及多個欄位和多個關鍵詞時。通常這一需求是透過應用層的程式碼進行處理,而不是在 Elasticsearch 中。
可能的解決方案參考如下:
欄位分析和排序 應用層處理 自定義評分查詢(function_score)
如果確實想在 Elasticsearch 裡解決這個問題,那麼指令碼排序可能是唯一可行的內建解決方案,儘管這樣可能會帶來效能和可維護性的問題。
在多欄位和多關鍵詞的情況下,使用 Painless 指令碼可能是最直接的方法來精確控制排序邏輯,但通常會犧牲一些效能。
簡而言之,Elasticsearch 本身可能不是最適合解決這一具體需求的工具。更合適的方式可能是結合應用層的邏輯來實現這一需求。
一般遇到類似問題,就得有理有據的和產品經理討論清楚需求,不要任憑產品經理“瞎指揮、瞎忽悠”。
那麼藉助指令碼如何實現呢?構造資料及拆解實現討論如下:
4.1 步驟1:建立索引及匯入資料
PUT /new_index_2023
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"content": {
"type": "text"
},
"question": {
"type": "text"
},
"answer": {
"type": "text"
}
}
}
}
POST /new_index_2023/_bulk
{"index": {}}
{"title": "基礎天天練有沒有單元練習?"}
{"index": {}}
{"title": "計算天天練是小學數學週週學的配套練習嗎?"}
{"index": {}}
{"title": "小學語文週週學和基礎天天練是否為配套練習?"}
{"index": {}}
{"title": "小學語文周天是否為配套練習"}
{"index": {}}
{"title": "計算天天練是週週學的配套練習嗎?"}
{"index": {}}
{"title": "小學數學周天是否為配套練習"}
{"index": {}}
{"title": "基礎天天練和53的區別是什麼?"}
{"index": {}}
{"title": "計算天天練有影片講解嗎?"}
{"index": {}}
{"title": "基礎天天練每個學期幾本?"}
4.2 步驟2:指令碼排序實現
如下實現僅針對需求1,指令碼僅供參考。
POST new_index_2023/_search
{
"query": {
"match": {
"title": "小學 天天"
}
},
"sort": [
{
"_script": {
"type": "number",
"script": {
"source": """
def title = doc['title.keyword'].value;
def keywordToFind = params.keywordToFind;
def schoolKeyword = params.schoolKeyword;
def indexSchool = title.indexOf(schoolKeyword);
def indexKeyword = title.indexOf(keywordToFind);
if (indexSchool < indexKeyword) {
return 1;
} else if (indexSchool > indexKeyword) {
return -1;
} else {
return 0;
}
""",
"lang": "painless",
"params": {
"keywordToFind": "天天",
"schoolKeyword": "小學"
}
},
"order": "desc"
}
}
]
}
指令碼目的:為了對搜尋結果進行排序,確保"title"欄位中"小學"出現在"天天"之前的文件排在前面。
指令碼實現邏輯解讀:
步驟 | 描述 |
---|---|
1 | 透過doc['title.keyword'].value 獲取當前文件的"title"欄位值並儲存在title 變數中。 |
2 | 使用Java的indexOf 方法,找到"小學"在"title"中的位置,並將這個位置儲存在indexSchool 變數中。 |
3 | 使用同樣的方法,找到"天天"在"title"中的位置,並將這個位置儲存在indexKeyword 變數中。 |
4 | 判斷兩個關鍵字的位置:如果"小學"在"天天"之前,返回1。 |
5 | 如果"小學"在"天天"之後,返回-1。 |
6 | 如果"小學"和"天天"在相同位置(實際上可能不會發生),返回0。 |
透過上述指令碼,Elasticsearch 會優先返回那些"title"欄位中"小學"出現在"天天"之前的文件。
讀到這裡,讀者可能會問,這換個詞咋辦?的確這不是普適的解決方案,而是定製的解決方案。
如果要“普適”,得我們們業務層面自己把控實現,這是大前提!
5、小結
如上看似複雜需求,是藉助拆解需求實現的任務分解。
請注意,這是一個非常簡化和特定的例子。更復雜的需求(例如,處理多個欄位或更多的關鍵詞)可能需要更復雜的指令碼。
但切記:如果排序邏輯變得太複雜或影響效能,可能需要考慮在應用層進行後處理,而不是依賴 Elasticsearch 的內部排序。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027827/viewspace-2985643/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 基於ElasticSearch實現商品的全文檢索檢索Elasticsearch
- 探索 Elasticsearch 8.X Terms Set 檢索的應用與原理Elasticsearch
- ElasticSearch 實現分詞全文檢索 - 概述Elasticsearch分詞
- ElasticSearch 實現分詞全文檢索 - delete-by-queryElasticsearch分詞delete
- [轉]23個最有用的Elasticsearch檢索技巧Elasticsearch
- ElasticSearch進階檢索Elasticsearch
- ElasticSearch入門檢索Elasticsearch
- ElasticSearch 億級資料檢索案例實戰Elasticsearch
- Elasticsearch加速檢索的Tips總結Elasticsearch
- 如何快速實現高併發短文檢索
- springboot ElasticSearch 簡單的全文檢索高亮Spring BootElasticsearch
- 23個最有用的ES檢索技巧(Java API實現)JavaAPI
- PostgreSQL一複合查詢SQL優化例子-(多個exists,範圍檢索,IN檢索,模糊檢索組合)SQL優化
- Elasticsearch 8.X 如何生成 TB 級的測試資料 ?Elasticsearch
- Mysql 如何實現全文檢索,關鍵詞跑分MySql
- 基於雜湊的影象檢索技術
- 讀書筆記:從Lucene到Elasticsearch:全文檢索實戰筆記Elasticsearch
- php + MongoDB + Sphinx 實現全文檢索PHPMongoDB
- GridLayoutManager 實現 複雜列布局
- 低程式碼平臺想要實現複雜的業務流程,這4個條件不能少!
- 前端雜談: 如何實現一個 Promise?前端Promise
- 前端雜談:如何實現一個Promise?前端Promise
- Elasticsearch 億級資料檢索效能最佳化案例實戰!Elasticsearch
- ES 24 - 如何通過Elasticsearch進行聚合檢索 (分組統計)Elasticsearch
- 雜湊表:如何實現word編輯器的拼寫檢查?
- ElasticSearch是如何實現分散式的?Elasticsearch分散式
- 基於 MongoTemplate 實現MongoDB的複雜查詢MongoDB
- 效能優化|多複雜表關聯查詢,你必須要知道的檢索姿勢!優化
- 一個複雜的json例子JSON
- 如何實現報表的批次列印需求
- 直面不確定性與非線性的複雜現實:邁向複雜性經濟 - Cilliers
- 如何搭建一個功能複雜的前端配置化框架(一)前端框架
- OpenCV特徵提取與影像檢索實現(附程式碼)OpenCV特徵
- 關於 Elasticsearch nested field /script 的一些複雜查詢Elasticsearch
- 基於Lucene的全文檢索實踐
- 如何降低軟體的複雜性?
- WPF使用Shape實現複雜線條動畫動畫
- 全球各城市、企業、園區的數字需求呈現出複雜、多元的樣貌。