Elasticsearch中URI Search和RequestBody Search分析


前言

Elasticsearch 作為一款分布式搜索工具,其搜索功能非常強大,本文主要介紹下 Elasticsearch 中高級搜索的使用。

Search APIs

搜索 APIs 按照查詢方式主要可以分為兩大類,那就是:URI earchRequest Body Search。在查詢語句中,一般使用 _search 來表示當前是一個搜索語句。

  • /_search:查詢集群上的所有索引數據,一般不建議這么使用。
  • index1,index2/_search:查詢指定一個或者多個索引的數據。
  • index*/_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 查詢,會查詢 namelonely 或者 wolf 的字段,而如果想把 lonely wolf 作為一個整體,則可以使用 Phrase 查詢。

布爾操作

在上面 Term 查詢中,我們發現當兩個 Term 查詢在一起,默認使用的是 or 的操作,而如果要使用 and,則可以使用布爾操作。

布爾操作支持以下符號(必須大寫):ANDORNOT&&||!。如下例子則只會查詢出 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)

這句話就只能查詢出 id4 的這條數據,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

這里表示允許 lonelywolf 之間插入一個其他字符,所以可以查詢出 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 分頁查詢也是通過 fromsize 來實現:

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*"]
}

這時候查詢會返回 idnameresult 三個字段。

使用 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 查詢,並徹底理解這兩種查詢方式的區別。

請關注我,和孤狼一起學習進步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM