前言
在 Elasticsearch 中,Term 查詢和全文查詢是兩種完全不同的處理方式,在上一篇我們也簡單對比了 Term 查詢和全文查詢中的 Phrase 中的區別,那么本文就徹底的來理清這兩種查詢之間的關系。
我們重新創建一個新的索引 index_002,並插入以下數據
POST /_bulk
{"index":{"_index":"index_002"}}
{"id":"1","name":"lonely wolf","address":null,"count":1}
{"index":{"_index":"index_002"}}
{"id":"2","name":"lonely hello wolf","address":[],"count":3}
{"index":{"_index":"index_002"}}
{"id":"3","name":"lonely hello word wolf","address":"[廣東]","count":1}
{"index":{"_index":"index_002"}}
{"id":"4","name":"Lonely Wolf","address":"['廣東','深圳']","count":2}
{"index":{"_index":"index_002"}}
{"id":"5","name":"wolf","address":null,"count":1}
Term 查詢
Term 查詢一般表達的是最小單位查詢,也就是說對我們傳入的關鍵字會作為一個整體進行查詢,而不會進行分詞。
如下查詢,滿足條件的只有第一條數據,需要注意的是對 text 類型字段需要加上 .keyword:
POST index_001/_search
{
"query": {
"term": {
"name.keyword": {
"value": "lonely wolf"
}
}
}
}
這里如果不加上 .keyword 則不會返回任何結果,這是因為 text 類型的字段會被倒排索引進行存儲,倒排索引會利用分析器將文本進行分詞,我們可以利用分詞器來查看下分詞結果:
POST /_analyze
{
"analyzer": "standard",
"text": ["lonely wolf"]
}

可以看到,lonely wolf 被分成了 lonely 和 wolf 兩個單詞,所以我們將 lonely wolf 作為一個進行查詢自然是無法查詢到結果的。
這里有個地方需要注意,如果我們存入的是大寫單詞,如 Lonely Wolf,分詞器也是一樣的結果,也就是會將大寫字母統一轉化為小寫進行存儲,所以進行全文查詢的時候也是無法查詢出結果。
exists 查詢
用來判定是否存在某一個字段,返回包含字段的任何索引值的文檔。
GET index_002/_search
{
"query": {
"exists": {
"field": "address"
}
}
}
這里返回的結果就是第三條和第四條數據,像 null 值和空數組 [] 不會被返回。
如果想要返回 null 值或者空數組 [] 的數據,那么可以利用 bool 查詢的 must_not 語句:
GET index_002/_search
{
"query": {
"bool": {
"must_not": [
{
"exists": {"field": "address"}
}
]
}
}
}
fuzzy 查詢
用於近似查詢,比如我們有時候在用百度搜索的時候,輸錯了字會被糾正:

一般情況下有一個單詞錯誤的情況下,fuzzy 查詢可以找到另一個近似的詞來代替,主要有以下場景:
- 修改一個單詞,如:
box--->fox。 - 移除一個單詞,如:
black-->lack。 - 插入一個單詞,如:
sic-->sick。 - 轉換兩個單詞順序,如:
act-->cat。
為了可以查詢到這種近似的單詞,fuzzy 查詢需要創建一個所有近似詞的集合,這樣搜索的時候就可以采用精確查詢找到近似的詞來代替查詢。
比如下面這個查詢就可以查詢出前面四條數據,同樣的,value 修改為 loneyl 或 lonelyy 或 loneyle 都能查詢出前面四條數據:
GET index_002/_search
{
"query": {
"fuzzy": {
"name": {
"value": "lonel"
}
}
}
}
ids 查詢
通過文檔 id 進行查詢返回,這里的 id 為文檔中的 _id。
GET index_002/_search
{
"query": {
"ids": {
"values": ["id1","id2"]
}
}
}
prefix 查詢
通過指定字段的前綴進行查詢。
GET index_002/_search
{
"query": {
"prefix": {
"name": {
"value": "lo"
}
}
}
}
range 查詢
通過范圍進行查詢。
GET index_002/_search
{
"query": {
"range": {
"id": {
"gte": 1,
"lte": 2
}
}
}
}
其中:
- gt:表示大於。
- gte:表示大於等於。
- lt:表示小於。
- lte:表示小於等於。
這種范圍查詢還可以用於日期的范圍查詢,此時將會對日期進行毫秒數轉換后進行查詢,如下面的例子就是查詢昨天到今天的區間,而且可以通過 time_zone 指定時區:
GET _search
{
"query": {
"range" : {
"timestamp" : {
"gte" : "now-1d/d",
"lt" : "now/d"
}
}
}
}
regexp 查詢
通過正則表達式進行查詢。如下例子可以查詢出 lon 開頭的所有數據:
GET index_002/_search
{
"query": {
"regexp": {
"name": "lon.*"
}
}
}
term 查詢
返回一個或者多個單詞精確匹配的文檔。
# 返回前面四條數據
GET index_002/_search
{
"query": {
"term": {
"name": {
"value": "lonely"
}
}
}
}
# 只返回第一條數據
GET index_002/_search
{
"query": {
"term": {
"name.keyword": {
"value": "lonely wolf"
}
}
}
}
terms 查詢
terms 查詢和 term 查詢是一個含義,區別只是 terms 可以一次精確匹配多個詞。
# 返回全部五條數據
GET index_002/_search
{
"query": {
"terms": {
"name": [
"lonely",
"wolf"
]
}
}
}
terms_set 查詢
terms_set 查詢和 terms 查詢是一樣的查詢規則,不同的是 terms_set 查詢可以定義匹配詞項的數量,定義的數量只能從文檔中的某一列中進行獲取或者使用腳本進行配置:
# 這里只能查詢第一和第三兩條數據,因為 `Wolf` 中的首字母大寫,無法被精確匹配上,count列不能是text類型
GET index_002/_search
{
"query": {
"terms_set": {
"name": {
"terms": [
"lonely",
"Wolf"
],
"minimum_should_match_field": "count"
}
}
}
}
type 查詢
指定類型查詢,type 類型在 7.0 版本已經標注為過期,8.0 版本已經被廢棄。
wildcard 查詢
通過通配符進行查詢,這個可以理解為是簡易版本的正則表達式查詢:
GET index_002/_search
{
"query": {
"wildcard": {
"name": {
"value": "lone*"
}
}
}
}
全文查詢
高級全文查詢通常用於對全文字段 text 類型(比如電子郵件的正文)進行全文查詢。全文查詢在搜索和索引時,都會對字段進行分詞處理,查詢之前會先對輸入的詞進行分詞處理,然后對每個詞項進行查詢,最后將結果進行合並,並根據算分結果將結果進行返回。
全文查詢也包括很多種,在這里我們主要介紹 match 查詢和 match_phrase 查詢。
match 查詢
match 查詢是執行全文搜索的標准查詢,包括模糊匹配選項。如下就是一個標准的 match 查詢語句:
# 返回全部5條數據
POST index_002/_search
{
"query": {
"match": {
"name": "lonely wolf"
}
}
}
對比 term 查詢:
# 沒有滿足條件的結果
POST index_002/_search
{
"query": {
"term": {
"name": "lonely wolf"
}
}
}
# 返回第一條數據
POST index_002/_search
{
"query": {
"term": {
"name.keyword": "lonely wolf"
}
}
}
根據上面幾個查詢的結果我們可以得出 term 查詢和全文 match 查詢的區別:
term查詢會將搜索關鍵字作為一個整體進行查詢。match查詢會將搜索關鍵字進行分詞,且分詞后默認是or的關系。
根據這兩個結論,也可以很明顯知道,一般不對 text 類型字段采用 term 查詢,因為 text 類型字段會被分詞索引,可能會導致無法被 term 查詢匹配出結果。
再看下面這個例子,會返回第二和第三兩條數據(分詞后的搜索和順序無關):
# 查詢出最少匹配中3個詞項的結果
POST index_002/_search
{
"query": {
"match": {
"name": {
"query": "hello wolf lonely",
"operator": "or",
"minimum_should_match": 3
}
}
}
}
match_phrase 查詢
match_phrase 會將輸入的搜索關鍵字作為一個短語進行查詢,這點看來類似於 term 查詢,但是 match_phrase 查詢內嵌了一個參數 slot 用來定義短語中允許的空隙,默認是 0 表示中間不允許有其他詞:
POST index_002/_search
{
"query": {
"match_phrase": {
"name": {
"query": "lonely wolf"
}
}
}
}
這條語句的結果就能查詢出第一和第四條數據,注意,雖然第四條數據中的 lonely wolf 是大寫字母開頭,但是索引的時候會將其轉為小寫進行索引,所以也能查詢出結果。
此時我們加入 slot=1 條件進行查詢,表示允許短語之間存在一個間隙,所以此時能查詢出第二條數據:
POST index_002/_search
{
"query": {
"match_phrase": {
"name": {
"query": "hello wolf lonely",
"slop": 1
}
}
}
}
總結
本文主要講述了 Term 查詢和全文查詢中 match 查詢的區別,總結起來主要有以下幾點:
Term查詢對搜索關鍵字不會進行分詞處理,而是作為一個整體進行查詢。- 全文查詢如
match等查詢,會對搜索關鍵字進行分詞,並對每個詞項進行搜索,默認or的關系進行合並,並最終算法返回結果。 - 對
Text類型字段,索引時會進行分詞,大寫字母會轉成小寫,所以如果用Term或者match_phrase查詢時要注意因分詞而對查詢結果產生的影響。
