前言
Elasticsearch
作為一款分布式搜索工具,其搜索功能非常強大,本文主要介紹下 Elasticsearch
中高級搜索的使用。
Search APIs
搜索 APIs
按照查詢方式主要可以分為兩大類,那就是:URI earch
和 Request Body Search
。在查詢語句中,一般使用 _search
來表示當前是一個搜索語句。
- /_search:查詢集群上的所有索引數據,一般不建議這么使用。
- index1,index2/_search:查詢指定一個或者多個索引的數據。
- index*/_search:利用通配符查詢當前集群上的索引數據。
URI Search
顧名思義,URI Search
指的是直接使用 URL
進行查詢,參數直接拼在 URL
上。
URI Search
中,主要有以下參數:
- q:指定查詢語句,使用
Query String Syntax
語法(KV
鍵值對)。 - df:默認字段,如果不指定,則會對所有字段進行查詢。
- sort:排序。
- explain:對每一個結果,都會返回
_explanation
結果,包含了當前數據分值的計算方式和結果。 - from/size:用於分頁,
from
表示從哪條數據開始,size
表示當前需要查詢多少條數據。 - _source:
false
表示不返回源數據(_source
字段),默認為true
。 - _source_includes:表示
_source
內只返回當前指定的字段。 - _source_excludes:表示
_source
內不返回當前指定的字段,當前參數優先級大於_source_includes
。 - timeout:指定超時時間,默認沒有超時時間。
bulk 插入演示數據
為了便於后面演示,我們通過 bulk
操作來批量插入一些比較直觀的數據:
POST index_001/_doc/_bulk
{"index":{}}
{"id":"1","name":"lonely wolf","result":true}
{"index":{}}
{"id":"2","name":"lonely hello wolf","result":true}
{"index":{}}
{"id":"3","name":"lonely hello word wolf","result":true}
{"index":{}}
{"id":"4","name":"lonely","result":false}
{"index":{}}
{"id":"5","name":"wolf","result":false}
或者執行以下語句:
POST /_bulk
{"index":{"_index":"index_001"}}
{"id":"1","name":"lonely wolf","result":true}
{"index":{"_index":"index_001"}}
{"id":"2","name":"lonely hello wolf","result":true}
{"index":{"_index":"index_001"}}
{"id":"3","name":"lonely hello word wolf","result":true}
{"index":{"_index":"index_001"}}
{"id":"4","name":"lonely","result":false}
{"index":{"_index":"index_001"}}
{"id":"5","name":"wolf","result":false}
基礎查詢
- 指定字段查詢:
# 指定name字段查詢
GET index_001/_search?q=name:wolf
- 使用默認字段查詢:
GET index_001/_search?q=wolf&df=name
上面這兩句話查詢效果是一樣的,均可以查詢出 4
條數據,執行 profile
分析一下,確實只匹配了 name
一個字段:
- 泛查詢(不指定任何字段)
GET index_001/_search?q=wolf
這條語句也是返回 4
條數據,但是這條語句和上面不同的是其沒有通過 q
指定篩選字段,也沒有通過 df
指定默認字段,所以會查詢所有字段:
執行 profile
查詢可以發現,這條語句會查詢所有字段,而且有些類型不匹配則會報錯,所以這種查詢效率是很低的,生產環境中應該盡量避免。
- 指定
source
查詢
再看下面的一個 source
查詢例子:
GET index_001/_search?q=name:wolf&_source_includes=name,result&_source_excludes=result&timeout=1ms
這個例子中因為同時指定了 _source_excludes
和 _source_includes
,但是因為 _source_excludes
優先級比較高,故而最終只會返回 name
一個字段:
Term 查詢
GET /index_001/_search?q=name:lonely wolf
這個查詢會返回所有數據,因為默認情況下這個查詢會使用 Term
查詢,會查詢 name
為 lonely
或者 wolf
的字段,而如果想把 lonely wolf
作為一個整體,則可以使用 Phrase
查詢。
布爾操作
在上面 Term
查詢中,我們發現當兩個 Term
查詢在一起,默認使用的是 or
的操作,而如果要使用 and
,則可以使用布爾操作。
布爾操作支持以下符號(必須大寫):AND
,OR
,NOT
,&&
,||
,!
。如下例子則只會查詢出 3
條數據。
GET /index_001/_search?q=name:lonely AND wolf
# 建議使用 () 來明確表示分組
GET /index_001/_search?q=name:(lonely AND wolf)
同時,布爾操作還支持一些高級查詢,如:+
表示 must
,-
表示 must not
:
GET /index_001/_search?q=name:(+lonely -wolf)
這句話就只能查詢出 id
為 4
的這條數據,name
含有 lonely
關鍵字且不含 wolf
關鍵字。
Phrase 查詢
假如我們想把一句話當成一個整體來查詢,則可以使用 Phrase
查詢:
GET /index_001/_search?q=name:"lonely wolf"
這個時候就只會查詢出一條數據。
通配符和正則查詢
通配符查詢中,?
表示 1
個字符,*
表示 0
或者多個字符。
# 沒有符合條件的數據GET /index_001/_search?q=name:lone?# 1-4條數據都符合條件GET /index_001/_search?q=name:lone*
通配符查詢是一種 like
查詢,效率相對會比較低,所以一般也不建議使用。
此外,還可以通過正則表達式查詢:
# 查詢出 id 為 2 或 3 的數據GET /index_001/_search?q=id:(2|3)
近似查詢
有些時候我們查百度的時候發現輸錯了字也能被查出來,這就是利用了近似查詢,如下所示:
# 輸錯一個字符,查詢不出結果GET /index_001/_search?q=name:loneyy# 允許一個字符錯誤,查詢出 4 條數據GET /index_001/_search?q=name:loneyy~1# 允許兩個字符錯誤,查詢出 4 條數據GET /index_001/_search?q=name:loniyy~2
另外,針對上面的 Phrase
查詢中,因為是把兩個單詞作為一個整體,那么也可以通過近似查詢來設置允許中間有其他字符,如下:
GET /index_001/_search?q=name:"lonely wolf" ~1
這里表示允許 lonely
和 wolf
之間插入一個其他字符,所以可以查詢出 2
條數據:
Request Body Query
Request Body
查詢是 Elasticsearch
中基於 json
格式提供的一種 DSL
語言(Query Domain Specific Language)。一般情況下,相比較於 URI Request
,雖然說 URI Query
也可以實現一定復雜程度的查詢,但是一般情況下我們還是更推薦使用 Request Body
查詢來實現更加復雜的一些組合查詢。
通過 URI Search
中能實現的搜索方式,都可以通過 Request Body
來實現,下面就讓我們一起來看看如何利用 Request Body
來進行搜索查詢。
分頁查詢
Request Body
分頁查詢也是通過 from
和 size
來實現:
POST index_001/_search
{
"from": 0,
"size": 2
}
排序
排序通過 sort
來實現。注意,默認 text
類型不能排序,如果需要排序則使用 field.keyword
來查詢:
POST index_001/_search
{
"sort": [
{
"name.keyword": {
"order": "desc"
}
}
]
}
source 查詢
同樣的,Request Body Query
也可以使用 source
來指定返回字段,而且也支持通配符的方式來指定:
POST index_001/_search
{
"_source": ["id","*e*"]
}
這時候查詢會返回 id
,name
和 result
三個字段。
使用 match 查詢
如果需要指定條件查詢,在 Request Body
查詢中則通過 match
來實現:
POST index_001/_search
{
"query": {
"match": {
"name": "lonely wolf"
}
}
}
同樣的,這個查詢默認的也是“或”的關系,所以這里也是能將 5
條數據全部查詢出來,如果要使用 AND
,則可以通過以下方式實現:
POST index_001/_search
{
"query": {
"match": {
"name": {
"query": "lonely wolf",
"operator": "and"
}
}
}
}
這樣子就只能查詢出前三條數據。
如果要查詢全部數據,則可以利用 match_all
進行查詢:
POST index_001/_search
{
"query": {
"match_all": {}
}
}
match phrase 查詢
上面的查詢中,即使指定了 and
,也能查詢出 3
條數據,如果需要精確查詢,那么可以使用 match phrase
查詢:
POST index_001/_search
{
"query": {
"match_phrase": {
"name": {
"query": "lonely wolf",
"slop": 0
}
}
}
}
這里如果不加 slot
,則默認為 0
,也就是不允許 lonely wolf
兩個單詞之間存在其他字符,這樣子就只能查詢出第一條數據。
腳本 script field 查詢
有時候我們需要利用腳本來對搜索結果進行進一步處理,這時候就可以腳本來實現一些功能,不過需要注意的是,text
字段默認也是不能使用腳本,如果需要是用同樣需要加上 .keyword
:
POST index_001/_search
{
"script_fields": {
"id-name": {
"script": {
"lang": "painless",
"source": "doc['id.keyword'].value + '-' + doc['name.keyword']"
}
}
},
"query": {
"match_all": {}
}
}
返回結果如下,新的結果會作為字段 id-name
返回:
總結
本文主要介紹了 Elasticsearch
中的兩種查詢方式,並分別介紹了一些非常常用的查詢方式,下一篇我們會專門介紹下本文提到的 Term
查詢和 Phrase
查詢,並徹底理解這兩種查詢方式的區別。
請關注我,和孤狼一起學習進步。