---
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