Elasticsearch從入門到放棄:再聊搜尋
阿新 • • 發佈:2020-07-14
在[前文](https://mp.weixin.qq.com/s?__biz=MzU0NTkzODUyMw==&mid=2247484107&idx=1&sn=6f3e9512a70afa6e2cc16c00c8dc3dba&chksm=fb640fffcc1386e90a49570e213d1e5f4b065538837019b43e62de261fe63c1d030bf5074fb3&token=2074787216&lang=zh_CN#rd)中我們曾經聊過搜尋文件的方法,Elasticsearch 一般適用於讀多寫少的場景,因此我們需要更多的關注讀操作。
Elasticsearch 提供的 Search API 可以分為 URI Search 和 Request Body Search 兩大類。從名稱上可以直觀的看出,URI Search 是使用URI的引數傳遞引數給 Elasticsearch,Request Body Search 則是將引數放到 Body 中進行傳遞,下面我們具體來看一下。
### URI Search
首先我們來看 URI Search 的一些引數。
- q 指定查詢語句,其使用的是 Query String Syntax
- df 指定預設欄位,如果不指定,則會查詢全部欄位
- Sort 對哪些欄位進行排序
- from/size 用於分頁
此外,我們還可以通過在請求體中指定 profile 引數來檢視查詢是如何被執行的。
你可以在Kibana中執行下面的查詢來看一下 Elasticsearch 的查詢是怎樣執行的。
``` bash
GET /movies/_search?q=2012
{
"profile": "true"
}
GET /movies/_search?q=title:2012
{
"profile": "true"
}
GET /movies/_search?q=2012&df=title
{
"profile": "true"
}
```
在上面這組查詢中,當我們指定了查詢欄位時, Elasticsearch 使用的 query type 是Term Query。
![term query](https://res.cloudinary.com/dxydgihag/image/upload/v1594441606/Blog/ES/05/es5-1.png)
與之對應的還有 Phrase Query。
#### Term
如果我們的查詢條件是 ```title:(Code Review)```,那麼它使用的就是 Term Query,它等價於查詢 title 中存在 Code 或 Review 的文件。
#### Phrase
如果我們的查詢條件是```title:"Code Review"```這樣用引號引起來的,那麼它使用的就是 Phrase Query,它等價於查詢同時存在 Code 和 Review 的文件,並且 Code 出現的順序必須在 Review 之前。
這裡你可能會有疑問,為什麼 Term Query 前後需要加括號,這是 Elasticsearch 中的分組概念,如果想要像我們說的那樣,在 titile 欄位中查詢存在 Code 或 Review 的文件,那麼就必須把它們作為一個分組進行查詢。這裡你可以自己動手試一下不加括號的情況,看一下 Elasticsearch 會如何執行。
Term Query 中還提供了很多種查詢語法,例如我們可以只用 AND、OR、NOT 這樣的字元進行布林操作(需要注意它們都必須大寫),也可以使用加號或減號表示 must 和 must not 的概念。同時區間、萬用字元、甚至是正則表示式查詢。
### Request Body Search
介紹完 URI Search,我們再一起學習一下 Request Body Search,其實在 Elasticsearch 中,Request Body Search 是更加常用的查詢方式。因為它能夠支援更多高階的使用方法。
在 Request Body Search 中,我們同樣是用 ```from``` 和 ```size``` 來進行分頁,預設的是從0開始,返回10個結果。
排序的方法也是使用 ```sort```,一般建議在“數字型”或“日期型”欄位上進行排序。
對於一些欄位比較多的文件,我們並不是每次查詢都需要全部的欄位,這時候就可以在 body 中加上``` _source``` 欄位來進行過濾。```_source```欄位可以支援萬用字元,例如```_source:["name*"]```,查詢中就只會返回欄位名是 name 開頭的欄位。
前面我們聊了 Term Query 和 Phrase Query,在 Request Body Search 中,我們使用 Match Query 來進行類似的操作。
``` bash
GET /movies/_search
{
"query": {
"match": {
"title": "Lord Rings"
}
}
}
```
在這個例子中,Elasticsearch 會幫我們查詢的是 title 中有 Lord 或 Rings 的文件,如果想要查詢 Lord 和 Rings,我們需要用到 operator 來進行修改。
``` bash
GET /movies/_search
{
"query": {
"match": {
"title": {
"query": "Lord Rings",
"operator": "and"
}
}
},
"profile": "true"
}
```
如果要使用 Phrase 查詢,只需要把上面的 ```match``` 替換為 ```match_phrase``` 即可。
在 Phrase 查詢中,可以使用 ```slot``` 引數來指定可以插入在中間的單詞數量。
``` bash
GET /movies/_search
{
"query": {
"match_phrase": {
"title": {
"query": "Lord Rings",
"slop": 2
}
}
},
"profile": "true"
}
```
### 總結
本文我們學習了 Elasticsearch 的兩種查詢方法:URI Search 和 Request Body Search 。這裡更加推薦使用 Request Body Search,因為它可以支援很多高階用法,這裡我們只介紹了一些比較常用的查詢方法,包括 Term Query 和 Phrase Query,也介紹了一些欄位的用法,包括分頁、排序、過濾欄位等。當然,Elasticsearch 的 Request Body Search 還支援很多其他引數,由於篇幅限制,就不再一一介紹了,大家在使用時可以自行查閱[官方文件](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html)。
最後多說一句,關於 Elasticsearch,我也是剛剛接觸,歡迎志同道合的同學一起