ElasticSearch進階檢索
- ElasticSearch進階檢索
-
- 檢索方式( _search)
-
- 使用文法
- 準備工作
- URL查詢
-
-
- 1.查詢所有(q=*)
- 2.按字段排序(sort)
- 3.分頁查詢(from&size)
- 4.傳回指定字段的查詢結果(source)
-
- DSL查詢
-
-
- 1.查詢所有(match_all)
- 2.傳回指定條數(size)
- 3.分頁查詢(from&size)
- 4.查詢的結果集中傳回指定字段(_source)
- 5.關鍵字查詢(term)
- 6.範圍查詢(range)
- 7.字首查詢(prefix)
- 8.通配符查詢(wildcard)
- 9.多id查詢(ids)
- 10.模糊查詢(fuzzy)
- 11.布爾查詢(bool)
- 12.高亮查詢(highlight)
- 13.多字段查詢(multi_match)
- 14.多字段分詞查詢(query_string)
-
ElasticSearch進階檢索
檢索方式( _search)
ES官方提供了兩中檢索方式:一種是通過 URL 參數進行搜尋,另一種是通過 DSL(Domain Specified Language) 進行搜尋。官方更推薦使用第二種方式第二種方式是基于傳遞JSON作為請求體(request body)格式與ES進行互動,這種方式更強大,更簡潔。

使用文法
URL查詢: GET /索引/類型/_search?參數
DSL查詢: GET /索引/類型/_search {}
準備工作
開始進階檢索之前先來準備一下測試資料
1.删除索引
DELETE /christy
2.建立索引、映射與類型
PUT /christy
{
"mappings": {
"user":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"bir":{
"type":"date"
},
"introduce":{
"type":"text"
},
"address":{
"type":"keyword"
}
}
}
}
}
3.批量插入資料
PUT /christy/user/_bulk
{"index":{}}
{"name":"Christy","age":20,"bir":"2001-01-01","introduce":"不要求很帥,像我這樣就可以了","address":"京師"}
{"index":{}}
{"name":"Tide","age":23,"bir":"1998-09-08","introduce":"魔鏡魔鏡誰是世界上最美的女人","address":"開封"}
{"index":{}}
{"name":"hardy","age":5,"bir":"2016-02-12","introduce":"調皮搗蛋我最行","address":"杭州"}
{"index":{}}
{"name":"Tom","age":18,"bir":"2003-12-12","introduce":"Jerry是我最好的朋友","address":"紐約"}
{"index":{}}
{"name":"Jerry","age":6,"bir":"2015-10-10","introduce":"沒有Tom的日子我真的好難過","address":"華盛頓"}
{"index":{}}
{"name":"布什","age":3,"bir":"2018-11-10","introduce":"我不是美國的那個總統,我隻是一條普拉多,沒有罵人的意思","address":"華盛頓"}
URL查詢
1.查詢所有(q=*)
文法:
GET /index/type/_search?q=*
。例如我想查詢索引
Christy
下
user
類型的所有資料,可以這麼寫:
GET /christy/user/_search?q=*
上述結果可以看到該指令成功傳回了查詢結果,也符合我們的預期。對于傳回結果中每個字段的意思如下圖
2.按字段排序(sort)
文法:
GET /index/type/_search?q=*&sort=fileName
。比如上面查詢出所有結果之後按年齡來排序,應該像下面這樣:
GET /christy/user/_search?q=*&sort=age
3.分頁查詢(from&size)
文法:
GET /index/type/_search?q=*&sort=fileName&size=count&from=(pageNumber-1)*size
。例如:我想取出按年齡排序後結果中的前兩天資料,應該像下面這樣寫
GET /christy/user/_search?q=*&sort=age&size=2&from=0
4.傳回指定字段的查詢結果(source)
文法:
GET /index/type/_search?q=*&size=1&from=0&_source=filedName1,...
。這個意思就是不需要傳回每條記錄的所有字段資訊,比如我隻想查詢并傳回使用者的姓名和年齡,那麼可以像下面這樣寫:
GET /christy/user/_search?q=*&size=1&from=0&_source=name,age
根據查詢的傳回結果我們可以看到隻傳回了我們定義的name和age兩個字段的值
DSL查詢
DSL查詢是官方推薦的查詢方式,相比較與URL,DSL能夠根據更複雜的條件來查詢,也是需要重點掌握的查詢方式
1.查詢所有(match_all)
GET /christy/user/_search
{
"query": { "match_all": {} }
}
2.傳回指定條數(size)
GET /christy/user/_search
{
"query": { "match_all": {} },
"size": 2
}
3.分頁查詢(from&size)
GET /christy/user/_search
{
"query": {"match_all": {}},
"size": 2,
"from": 1
}
from是從0開始的,上面的分頁中我們從1開始取兩條,就将第一條使用者christy的資料給過濾掉了,傳回結果的第一條資料應該是使用者Tide
4.查詢的結果集中傳回指定字段(_source)
GET /christy/user/_search
{
"query": {"match_all": {}},
"size": 2,
"from": 1,
"_source":["name","age"]
}
通過傳回結果我們可以看到在上面分頁結果的基礎上隻傳回使用者的name和age也是沒有問題的。這裡要注意的是指令中_source的參數是以數組的方式傳遞的
5.關鍵字查詢(term)
GET /christy/user/_search
{
"query": {
"term": {
"address": {
"value": "開封"
}
}
}
}
NOTE1: 通過使用term查詢得知ES中預設使用分詞器為标準分詞器(StandardAnalyzer),标準分詞器對于英文單詞分詞,對于中文單字分詞。
NOTE2: 通過使用term查詢得知,在ES的Mapping Type 中 keyword , date ,integer, long , double , boolean or ip 這些類型不分詞,隻有text類型分詞。
上面兩條NOTE是什麼意思呢?标準分詞器将type類型為text的字段值分詞後,隻能按照單個漢字或者英文單詞來查詢,否則查詢不到資料;比如我們測試資料的
name
類型是text,其中有一條名字叫做"布什"的普拉多,我們這個時候直接搜尋布什是什麼都搜尋不到的,但是搜尋單個的布或者什是可以找到這隻可愛的普拉多的,就像下圖示範的一樣
6.範圍查詢(range)
GET /christy/user/_search
{
"query": {
"range": {
"age": {
"gte": 8,
"lte": 30
}
}
}
}
上面我們看到的
gte
和
lte
分别是
大于等于
和
小于等于
的意思,上面的指令查詢的是年齡大于等于8歲并且小于等于30歲的使用者。如果需要查詢大于8歲并且小于30歲的使用者我們隻需要把gte和lte改成gt和lt就行了;
7.字首查詢(prefix)
GET /christy/user/_search
{
"query": {
"prefix": {
"content": {
"introduce": "最"
}
}
}
}
字首查詢關鍵字prefix用來檢索含有指定字首關鍵字的相關文檔。比如上面我們查詢introduce字段包含 最
的使用者。
8.通配符查詢(wildcard)
通配符查詢關鍵字wildcard說明:
?
:用來比對一個字元
*
:用來比對任意多個字元
GET /christy/user/_search
{
"query": {
"wildcard": {
"introduce": {
"value": "jerr*"
}
}
}
}
NOTE:我們目前還沒有配置分詞器,ES用的是自帶的标準分詞器,一個漢字一個詞,是以這裡通配符查詢不能測試漢字,隻能測試英文。
9.多id查詢(ids)
顧名思義,多id查詢就是可以根據多個記錄的id來查詢多條記錄。這個一般都是在實際應用中查詢多個記錄清單或者詳情
GET /christy/user/_search
{
"query": {
"ids": {
"values": ["OKEuB3kBVQPOYI_dp2GY","PKEuB3kBVQPOYI_dp2GY"]
}
}
}
10.模糊查詢(fuzzy)
# fuzzy 模糊查詢 最大模糊錯誤 必須在0-2之間
# 搜尋關鍵詞長度為 2 不允許存在模糊 0
# 搜尋關鍵詞長度為3-5 允許一次模糊 0 1
# 搜尋關鍵詞長度大于5 允許最大2模糊
GET /christy/user/_search
{
"query": {
"fuzzy": {
"introduce":"jerry"
}
}
}
首先,我們先示範第一種情況:搜尋關鍵詞長度為2,不允許存在模糊
address的類型是 keyword
不分詞,我們輸入京師是可以查到資料的,但是我們輸入京濕是查詢不到的
現在我們來示範第二種情況:搜尋關鍵字長度3-5,最大隻允許一個模糊字元
按照 introduce
查找jerry是可以查詢到資料的,我們改錯一個字元也沒有問題,但是改錯兩個字元就不行了
最後我們來示範最後一種情況,搜尋關鍵字大于5時,最大隻允許模糊兩個字元,為此我們先準備一條資料
PUT /christy/user/_bulk
{"index":{}}
{"name":"ElasticSearch","age":20,"bir":"2001-01-01","introduce":"ElasticSearch是最牛逼的搜尋的引擎","address":"china"}
然後我們就以
elasticsearch
為搜尋關鍵字進行查詢
效果如上圖,這裡就不解釋了
11.布爾查詢(bool)
bool關鍵字用來組合多個條件實作複雜查詢,這也是bool查詢的強大之處
must
:相當于&&,同時成立
should
:相當于||,滿足一個條件就行
must_not
:相當于!,不能滿足任何一個
GET /christy/user/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 0,
"lte": 30
}
}
}
],
"must_not": [
{"wildcard": {
"introduce": {
"value": "jerr*"
}
}}
],
"should": [
{
"term": {
"age": {
"value": "20"
}
}
},
{
"term": {
"introduce": {
"value": "tom"
}
}
}
]
}
}
}
12.高亮查詢(highlight)
高亮關鍵字highlight可以讓符合條件的文檔中的關鍵字高亮,類似于下面這樣
GET /christy/user/_search
{
"query": {
"term": {
"introduce": {
"value": "elasticsearch"
}
}
},
# highlight不是直接對結果進行高亮,而是對結果二次渲染高亮
"highlight": {
# fields意思是對哪些字段比對出來的結果進行高亮,雖然我們上面是查詢introduce裡面的elasticsearch,但是如果我們其他的字段比如‘name’中也有elasticsearch或者其他字段中也有,并且我們也希望高亮,那麼我們像下面這樣寫成*即可
"fields": {
"*": {}
}
}
}
查詢結果我們也看到了,ES确實将查詢出來的關鍵字特别處理了,前後加上了,這是斜體的意思,如果我們想實作百度的那種加紅處理,需要自定義和
pre_tags
有人說上面的測試結果隻把
post_tags
裡面查詢出來的結果高亮了,
introduce
裡面的沒有高亮啊?那是因為沒有加上
name
這個屬性,他的意思是是否隻開啟查詢字段高亮。屬性值必須設定成false才能針對所有字段高亮
require_field_match
GET /christy/user/_search
{
"query":{
"term":{
"introduce":"elasticsearch"
}
},
"highlight": {
"pre_tags": ["<span style='color:red'>"],
"post_tags": ["</span>"],
"require_field_match":false,
"fields": {
"*":{}
}
}
}
13.多字段查詢(multi_match)
GET /christy/user/_search
{
"query": {
"multi_match": {
"query": "tom",
"fields": ["name","introduce"] #這裡寫要檢索的指定字段
}
}
}
多字段查詢需要注意
1.如果搜尋的字段分詞,他會對query進行先分詞,後查詢
2.如果搜尋的字段部分詞,他會直接使用query字元串整體進行搜尋
我們使用
tom紐約
進行搜尋,由于
introduce
是text類型的,他是分詞的;
address
是keyword類型的部分詞,是以在搜尋introduce的時候先對query進行分詞,而查詢address的時候不分詞,直接使用整體進行查詢。是以在使用多字段查詢的時候,查詢的字段最好是分詞的字段
14.多字段分詞查詢(query_string)
多字段分詞查詢顧名思義可以對查詢關鍵字進行分詞,而且可以指定分詞器,就是這樣一個牛逼的存在
GET /christy/user/_search
{
"query": {
"query_string": {
"default_field": "introduce",
"query": "tom和jerry"
}
}
}
當然們也可以像下面這樣寫
GET /christy/user/_search
{
"query": {
"query_string": {
"fields": ["address","introduce"],
"query": "tom和jerry"
}
}
}
這就實作了一個類似上面我們說的多字段查詢。上面我們也說了這個可以指定分詞器,可以像下面這樣
GET /christy/user/_search
{
"query": {
"query_string": {
"fields": ["address","introduce"],
"query": "jerry華盛頓",
"analyzer": "ik_max_word"
}
}
}
這裡我們除了标準分詞器還沒有安裝其他分詞器,上面我們提到的
ik_max_word
下節我們再講<( ̄▽ ̄)/