--- title: 全文搜索 tags: ES筆記 description: View the slide with "Slide Mode". --- # 全文搜索 ## 目錄 0. [簡介](#0\.簡介) 1. [匹配查詢](#1\.匹配查詢) 2. [多詞查詢](#2\.多詞查詢) 3. [布林查詢](#3\.布林查詢) 4. [布林與match的等價關係](#4\.布林與match的等價關係) 5. [對查詢子句設權重](#5\.對查詢子句設權重) 6. [分析控制](#6\.分析控制) 7. [關聯失效](#7\.關聯失效) --- ## 0.簡介 - 怎樣對全文字段(full-text fields)進行檢索以找到相關度最高的文檔。 - 全文檢索最重要的兩個方面是: - <font color=red>相關度(Relevance)</font> 根據文檔與查詢的相關程度對結果集進行排序的能力。相關度可以使用<font color=blue>TF/IDF</font>、地理位置相近程度、<font color=blue>模糊相似度</font>或其他算法計算。 - <font color=red>分析(Analysis)</font> 將一段文本轉換為一組唯一的、標準化了的標記(token),用以(a)創建倒排索引,(b)查詢倒排索引。 >[name=昱齊] 唯一的是什麼意思 ### 基於短語vs. 全文 雖然所有的查詢都會進行相關度計算,但不是所有的查詢都有分析階段。而且像`bool`或`function_score`這樣的查詢<font color=blue>並不在文本字段執行</font>。文本查詢可以分為兩大類: 1. 基於短語(<font color=red>Term-based</font>)的查詢: 像`term`或`fuzzy`一類的查詢是低級查詢,它們沒有分析階段。這些查詢在單一的短語上執行。例如對單詞`'Foo'`的`term`查詢會<font color=blue>在倒排索引裡精確地查找`'Foo'`這個詞</font>,並對每個包含這個單詞的文檔計算TF/IDF相關度`'_score'`。 牢記`term`查詢<font color=blue>只在倒排查詢裡精確地查找特定短語,而不會匹配短語的其它變形</font>,如`foo`或`FOO`。不管短語怎樣被加入索引,都只匹配倒排索引裡的準確值。如果你在一個設置了`'not_analyzed'`的字段為`'["Foo", "Bar"]'`建索引,或者在一個用`'whitespace'`解析器解析的字段為`'Foo Bar'`建索引,都會在倒排索引裡加入兩個索引`'Foo'`和`'Bar'` >[name=昱齊]not_analyzed就是keyword,舊版es稱為not_analyzed ### 全文(Full-text)檢索 `match`和`query_string`這樣的查詢是高級查詢,它們會對字段進行分析: - 如果檢索一個`'date'`或`'integer'`字段,它們會把查詢語句作為日期或者整數格式數據。 - 如果檢索一個準確值( `'not_analyzed'`)字符串字段,它們會把整個查詢語句作為一個短語。 - 如果檢索一個全文( `'analyzed'`)字段 1. 查詢會先用適當的解析器解析查詢語句 2. 產生需要查詢的<font color=blue>短語列表</font> 3. 然後對列表中的每個短語執行低級查詢 4. 合併查詢結果,得到最終的文檔相關度。 >[name=昱齊]簡單來說,使用match來做全文搜索時,會reduce to 多個term query ### 與過濾器對比 - 如果確實要查詢一個準確值字段( 'not_analyzed'),需要考慮<font color=blue>使用查詢還是過濾器</font>。 - 單一短語的查詢通常相當於是/否問題,用<font color=blue>過濾器</font>可以更好的描述這類查詢,並且<font color=blue>過濾器緩存</font>可以提升性能 ```htmlmixed= GET /_search { "query": { "filtered": { "filter": { "term": { "gender": "female" } } } } } ``` >[name=昱齊] 過濾器緩存的用途,以及如何寫過濾器 ## 1.匹配查詢 - 使用`match`,match查詢的一個主要用途是進行全文搜索 ### 建立範例資料 ```htmlmixed= DELETE /my_index <1> PUT /my_index { "settings": { "number_of_shards": 1 }} <2> POST /my_index/my_type/_bulk { "index": { "_id": 1 }} { "title": "The quick brown fox" } { "index": { "_id": 2 }} { "title": "The quick brown fox jumps over the lazy dog" } { "index": { "_id": 3 }} { "title": "The quick brown fox jumps over the quick dog" } { "index": { "_id": 4 }} { "title": "Brown fox brown dog" } ``` ### 單詞查詢 第一個例子解釋了當使用match查詢進行單詞全文搜索時發生了什麼: ```htmlmixed= GET /my_index/my_type/_search { "query": { "match": { "title": "QUICK!" } } } ``` <font color=red>Elasticsearch通過下面的步驟執行match查詢:</font> 1. 檢查field類型 title字段是一個字符串( analyzed),所以該查詢字符串也需要被分析( analyzed) 2. 分析查詢字符串 查詢詞QUICK!經過標準分析器的分析後變成單詞quick。因為我們只有一個查詢詞,因此match查詢可以<font color=blue>以一種低級別term查詢的方式執行</font>。 3. 找到匹配的文檔 term查詢在倒排索引中搜索quick,並且返回包含該詞的文檔。在這個例子中,返回的文檔是1,2,3。 4. 為每個文檔打分 term查詢綜合考慮 1. 詞頻(每篇文檔title字段包含quick的次數) 2. 逆文檔頻率(在全部文檔中title字段包含quick的次數) 3. 包含quick的文檔的字段長度(長度越短越相關) - 來計算每篇文檔的相關性得分_score 這個過程之後我們將得到以下結果(簡化後): ```json= "hits": [ { "_id": "1", "_score": 0.5, <1> "_source": { "title": "The quick brown fox" } }, { "_id": "3", "_score": 0.44194174, <2> "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "2", "_score": 0.3125, <2> "_source": { "title": "The quick brown fox jumps over the lazy dog" } } ] ``` <1>文檔1最相關,因為title<font color=blue>最短</font>,意味著quick在語義中起比較大的作用。 <2>文檔3比文檔2更相關,因為在文檔3中quick出現了<font color=blue>兩次</font>。 ## 2.多詞查詢 ```htmlmixed= GET /my_index/my_type/_search { "query": { "match": { "title": "BROWN DOG!" } } } ``` 查詢結果 ```json= { "hits": [ { "_id": "4", "_score": 0.73185337, <1> "_source": { "title": "Brown fox brown dog" } }, { "_id": "2", "_score": 0.47486103, <2> "_source": { "title": "The quick brown fox jumps over the lazy dog" } }, { "_id": "3", "_score": 0.47486103, <2> "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "1", "_score": 0.11914785, <3> "_source": { "title": "The quick brown fox" } } ] } ``` <1> 文檔4的相關度最高,因為包含兩個"brown"和一個"dog"。 <2> 文檔2和3都包含一個"brown"和一個"dog",且'title'字段長度相同,所以相關度相等。 <3> 文檔1只包含一个"brown",不包含"dog",所以相關度最低。 :::info 因為match查詢需要查詢兩個關鍵詞:`"brown"`和`"dog"`,在內部會執行兩個term查詢並綜合二者的結果得到最終的結果。<font color=red>`match`的實現方式是將兩個查詢放入一個查詢</font>,`bool`查詢在之前的章節已經介紹過。 重要的一點是,`'title'`字段<font color=red>包含至少一個查詢關鍵字</font>的文檔都被認為是符合查詢條件的。匹配的單詞數越多,文檔的相關度越高。 ::: ### 提高精度 當我們想得到的是匹配`'brown AND dog'`的文檔,而非`'brown OR dog'`。 `match`查詢接受一個<font color=red>`'operator'`參數</font>,<font color=blue>默認值為`or`</font>。如果要求所有查詢關鍵字都匹配,可以更改參數值為`and`: ```htmlmixed= GET /my_index/my_type/_search { "query": { "match": { "title": { <1> "query": "BROWN DOG!", "operator": "and" } } } } ``` ### 控制精度 - 在`all`和`any`之間的選擇有點過於非黑即白。如果用戶指定了5個查詢關鍵字,而一個文檔只包含了其中的4個?將`'operator'`設置為`'and'`會排除這個文檔 - 因此我們需要介於二者之間的選項 `match`查詢有`'minimum_should_match'`參數,參數值表示被視為相關的文檔必須匹配的關鍵詞個數。參數值可以設為整數,也可以設置為百分數。因為不能提前確定用戶輸入的查詢關鍵詞個數,使用百分數也很合理。 ```htmlmixed= GET /my_index/my_type/_search { "query": { "match": { "title": { "query": "quick brown dog", "minimum_should_match": "75%" } } } } ``` - 當`'minimum_should_match'`被設置為百分數時,查詢進行如下:在上面的例子裡,`'75%'`會被下舍為`'66.6%'`,也就是2個關鍵詞 - 不論參數值為多少,進入結果集的文檔至少應匹配一個關鍵詞。 ## 3.布林查詢 - 怎樣用<font color=red>布林</font>組合出查詢子句 - 查詢會做精細的判斷.他們不僅決定一個文檔是否要添加到結果集,而且還要計算文檔的相關性 - 布林查詢接受多個用<font color=#F0B5A5>`must`, `must_not`, and `should`</font>的查詢子句 流程: 1. 首先會看`must`跟`must_not`,進行過濾 2. 得分計算 布爾查詢通過把所有<font color=blue>符合must和should的子句得分加起來</font>,然後除以must和should子句的總數為每個文檔計算相關性得分。 must_not子句並不影響得分;他們存在的意義是排除已經被包含的文檔。 ### should的精度控制 跟match一樣,可以有個threhold ```htmlmixed= GET /my_index/my_type/_search { "query": { "bool": { "should": [ { "match": { "title": "brown" }}, { "match": { "title": "fox" }}, { "match": { "title": "dog" }} ], "minimum_should_match": 2 } } } ``` ## 4.布林與match的等價關係 ## 5.對查詢子句設權重 boost子句 ## 6.分析控制 分詞器流程 ## 7.關聯失效 本地IDF和全局IDF