背景
- 首先看個例子,有兩個 doc,一條是 albino elephant,一條是 elephant elephant
PUT test_elephant/_doc/1
{
"title_text":"elephant",
"body_text":"elephant"
}
PUT test_elephant/_doc/2
{
"title_text":"albino",
"body_text":"elephant"
}
複製代碼
- 用戶想查
albino elephant
, 因而咱們就這樣寫了一條 query 語句,指望能夠召回 doc 2
GET test_elephant/_search
{
"query": {
"query_string": {
"fields": ["title_text","body_text"],
"query": "albino elephant"
}
}
}
複製代碼
- 可是實際結果卻和咱們預期的不同,兩個 doc 評分如出一轍,那麼這是爲何呢?
doc1 max(title_text:elephant,body_text:elephant)
doc2 max(title_text:albino,body_text:elephant)
複製代碼
- 而由於 elephant 和 albino 在 title 字段中都出現了一次,因此分數同樣,都是0.69
- 那麼爲何呢?
- 咱們經過
_validate/query?rewrite=true
能夠看到這個 query 被翻譯成
以字段爲中心(field-centric) VS 以詞爲中心(term-centric)
- 上述的那個例子就是以字段爲中心中經典的『白化象問題』,那麼到底什麼是以字段爲中心,什麼是以詞爲中心呢?下圖
- 左邊是爲 以字段爲中心,可見,字段爲中心爲query 在各個字段分別算分,而後按必定 function 求最終結果,也就是其實最終的結果也是整個 query 在哪一個字段中表現最好。
- 這種適用於用戶意圖只會命中一個字段時適用
- 優點:符合結構化語義,易於控制不一樣字段權重
- 問題:
- 白化象問題(albino elephant) — 有更多搜索詞匹配的文檔沒有被排在靠前的位置
- 信號衝突(signal discordance) — 多字段 idf 不一,排序難被用戶理解。好比一我的常常作演員不多作導演,而後搜索的時候,導演字段的分數就會很是高,形成當導演的電影排序靠前,形成用戶困擾
- 右邊爲 以詞爲中心,以詞爲中心則是詞在不一樣字段中的分數,經過必定 function 算出(圖中爲 max),而後再將各個詞的分數以必定 function 結合做爲總分。
- 這種實際上就是用戶並不關係匹配的是什麼字段,不關心文檔結構,關心的只是匹配到了哪些詞。
- 優點:更符合用戶心智,用戶每每難以瞭解數據的結構
- 問題:很差控制不一樣字段權重,實現複雜
ES 中的多字段檢索方式
查看真實檢索語句
- 利用 _validate/query?rewrite=true 能夠看到真實傳個 lucene 的語句,即可看出其真實邏輯。也可用
explain=true
能夠看見部分中間過程,可是效果沒有 rewrite 直觀
經常使用多字段檢索
- 下面利用 validate 對
title(keyword 字段)
, title_text(ik 分詞器)
和 body_text(ik 分詞器)
進行查詢,查詢內容爲 ZSearch 通用搜索
- MultiMatch
- best_fields - 字段中心,字段間 max ,可用 tie_breaker 調整字段間關係
(title:ZSearch 通用搜索 | (title_text:zsearch title_text:通用 title_text:搜索) | (body_text:zsearch body_text:通用 body_text:搜索))
- most_fields - 字段中心 字段間相加
title:ZSearch 通用搜索 (title_text:zsearch title_text:通用 title_text:搜索) (body_text:zsearch body_text:通用 body_text:搜索)
- cross_fields - 詞中心 詞在不一樣字段間取 max,而後相加
(((title_text:zsearch | body_text:zsearch) (title_text:通用 | body_text:通用) (title_text:搜索 | body_text:搜索)) | title:ZSearch 通用搜索)
- QueryString - 字段中心 同 best_fields
(title:ZSearch 通用搜索 | (title_text:zsearch title_text:通用 title_text:搜索) | (body_text:zsearch body_text:通用 body_text:搜索))
- SimpleQueryString 詞中心,但詞在不一樣字段間爲相加
(title_text:zsearch title:ZSearch body_text:zsearch) ((title_text:通用 title_text:搜索) title:通用搜索 (body_text:通用 body_text:搜索))
- 須要注意的是詞爲中心的查詢方式均會受分詞器影響,其中 simple query string 和 cross 採起了兩種不一樣的實現方式
- simple query string 爲簡單按空格分割,而後直接丟入各字段進行查詢,所以是分詞前的以詞爲中心,而不是最終的,及時設置了 analyzer 也依舊如此
- cross_field 則是採起首先按分詞器進行分組,一樣的分詞器內以詞爲中心在多字段進行查詢,不一樣的分詞器直接按字段取 max
- 另外,多字段查詢的
minimum_should_match
也只與一級子句(最外邊的括號內的)有關,內部再分詞均不會做用
擴展閱讀
如何實現字段中心和詞中心相結合
- 類似字段,按用戶意圖將字段分組,好比 姓 和 名 兩個字段合併 姓名 一個字段,將不一樣意圖的搜索徹底分開
- 以詞爲中心進行兜底,以字段爲中心進行加成,以下
多字段算分在信息檢索領域的嘗試
- 傳統BM25在計算相關性時把文檔當作整體來考慮,但隨着搜索技術的發展。文檔慢慢的被結構化數據所取代。每一個文檔都會被切分紅多個獨立的域,尤爲是垂直化的搜索。好比網頁有可能被切分紅標題,內容,主題詞等域,這些域對文章主題的貢獻不能同等對待,因此權重就要有所偏重。
- BM25沒有考慮這點。因此BM25F在此基礎上作了一些改進,就是再也不單單的將單詞做爲個體考慮,而且將文檔也依照field劃分爲個體考慮,因此BM25F是每個單詞在各個field中分值的加權求和。
參考資料