elasticsearch之布爾查詢
前言
布爾查詢是最常用的組合查詢,根據子查詢的規則,只有當文檔滿足所有子查詢條件時,elasticsearch引擎才將結果返回。布爾查詢支持的子查詢條件共4中:
- must(and)
- should(or)
- must_not(not)
- filter
下面我們來看看每個子查詢條件都是怎么玩的。
准備數據
PUT zhifou/doc/1
{
"name":"顧老二",
"age":30,
"from": "gu",
"desc": "皮膚黑、武器長、性格直",
"tags": ["黑", "長", "直"]
}
PUT zhifou/doc/2
{
"name":"大娘子",
"age":18,
"from":"sheng",
"desc":"膚白貌美,嬌憨可愛",
"tags":["白", "富","美"]
}
PUT zhifou/doc/3
{
"name":"龍套偏房",
"age":22,
"from":"gu",
"desc":"mmp,沒怎么看,不知道怎么形容",
"tags":["造數據", "真","難"]
}
PUT zhifou/doc/4
{
"name":"石頭",
"age":29,
"from":"gu",
"desc":"粗中有細,狐假虎威",
"tags":["粗", "大","猛"]
}
PUT zhifou/doc/5
{
"name":"魏行首",
"age":25,
"from":"廣雲台",
"desc":"仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
"tags":["閉月","羞花"]
}
must
現在,我們用布爾查詢所有from屬性為gu的數據:
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
]
}
}
}
上例中,我們通過在bool屬性(字段)內使用must來作為查詢條件,那么條件是什么呢?條件同樣被match包圍,就是from為gu的所有數據。
這里需要注意的是must字段對應的是個列表,也就是說可以有多個並列的查詢條件,一個文檔滿足各個子條件后才最終返回。
結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "4",
"_score" : 0.6931472,
"_source" : {
"name" : "石頭",
"age" : 29,
"from" : "gu",
"desc" : "粗中有細,狐假虎威",
"tags" : [
"粗",
"大",
"猛"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "3",
"_score" : 0.2876821,
"_source" : {
"name" : "龍套偏房",
"age" : 22,
"from" : "gu",
"desc" : "mmp,沒怎么看,不知道怎么形容",
"tags" : [
"造數據",
"真",
"難"
]
}
}
]
}
}
上例中,可以看到,所有from屬性為gu的數據查詢出來了。
那么,我們想要查詢from為gu,並且age為30的數據怎么搞呢?
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"age": 30
}
}
]
}
}
}
上例中,在must列表中,在增加一個age為30的條件。
結果如下:
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.287682,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 1.287682,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
}
]
}
}
上例,符合條件的數據被成功查詢出來了。
注意:現在你可能慢慢發現一個現象,所有屬性值為列表的,都可以實現多個條件並列存在
should
那么,如果要查詢只要是from為gu或者tags為閉月的數據怎么搞?
GET zhifou/doc/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"tags": "閉月"
}
}
]
}
}
}
上例中,或關系的不能用must的了,而是要用should,只要符合其中一個條件就返回。
結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 4,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "4",
"_score" : 0.6931472,
"_source" : {
"name" : "石頭",
"age" : 29,
"from" : "gu",
"desc" : "粗中有細,狐假虎威",
"tags" : [
"粗",
"大",
"猛"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "5",
"_score" : 0.5753642,
"_source" : {
"name" : "魏行首",
"age" : 25,
"from" : "廣雲台",
"desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
"tags" : [
"閉月",
"羞花"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "3",
"_score" : 0.2876821,
"_source" : {
"name" : "龍套偏房",
"age" : 22,
"from" : "gu",
"desc" : "mmp,沒怎么看,不知道怎么形容",
"tags" : [
"造數據",
"真",
"難"
]
}
}
]
}
}
返回了所有符合條件的結果。
must_not
那么,如果我想要查詢from既不是gu並且tags也不是可愛,還有age不是18的數據怎么辦?
GET zhifou/doc/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"tags": "可愛"
}
},
{
"match": {
"age": 18
}
}
]
}
}
}
上例中,must和should都不能使用,而是使用must_not,又在內增加了一個age為18的條件。
結果如下:
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "5",
"_score" : 1.0,
"_source" : {
"name" : "魏行首",
"age" : 25,
"from" : "廣雲台",
"desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
"tags" : [
"閉月",
"羞花"
]
}
}
]
}
}
上例中,只有魏行首這一條數據,因為只有魏行首既不是顧家的人,標簽沒有可愛那一項,年齡也不等於18!
這里有點需要補充,條件中age對應的18你寫成整形還是字符串都沒啥......讓灑家感受到一種比Python還自由奔放的氣息!像極了JavaScript!
filter
那么,如果要查詢from為gu,age大於25的數據怎么查?
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"gt": 25
}
}
}
}
}
}
這里就用到了filter條件過濾查詢,過濾條件的范圍用range表示,gt表示大於,大於多少呢?是25。
結果如下:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "4",
"_score" : 0.6931472,
"_source" : {
"name" : "石頭",
"age" : 29,
"from" : "gu",
"desc" : "粗中有細,狐假虎威",
"tags" : [
"粗",
"大",
"猛"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
}
]
}
}
上例中,age大於25的條件都已經篩選出來了。
那么要查詢from是gu,age大於等於30的數據呢?
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"gte": 30
}
}
}
}
}
}
上例中,大於等於用gte表示。
結果如下:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
}
]
}
}
那么,要查詢age小於25的呢?
GET zhifou/doc/_search
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"lt": 25
}
}
}
}
}
}
上例中,小於用lt表示,結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.0,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "2",
"_score" : 0.0,
"_source" : {
"name" : "大娘子",
"age" : 18,
"from" : "sheng",
"desc" : "膚白貌美,嬌憨可愛",
"tags" : [
"白",
"富",
"美"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "3",
"_score" : 0.0,
"_source" : {
"name" : "龍套偏房",
"age" : 22,
"from" : "gu",
"desc" : "mmp,沒怎么看,不知道怎么形容",
"tags" : [
"造數據",
"真",
"難"
]
}
}
]
}
}
在查詢一個age小於等於18的怎么辦呢?
GET zhifou/doc/_search
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"lte": 18
}
}
}
}
}
}
上例中,小於等於用lte表示。結果如下:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.0,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "2",
"_score" : 0.0,
"_source" : {
"name" : "大娘子",
"age" : 18,
"from" : "sheng",
"desc" : "膚白貌美,嬌憨可愛",
"tags" : [
"白",
"富",
"美"
]
}
}
]
}
}
要查詢from是gu,age在25~30之間的怎么查?
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"gte": 25,
"lte": 30
}
}
}
}
}
}
上例中,使用lte和gte來限定范圍。結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "4",
"_score" : 0.6931472,
"_source" : {
"name" : "石頭",
"age" : 29,
"from" : "gu",
"desc" : "粗中有細,狐假虎威",
"tags" : [
"粗",
"大",
"猛"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "顧老二",
"age" : 30,
"from" : "gu",
"desc" : "皮膚黑、武器長、性格直",
"tags" : [
"黑",
"長",
"直"
]
}
}
]
}
}
那么,要查詢from是sheng,age小於等於25的怎么查呢?其實結果,我們可能已經想到了,只有一條,因為只有盛家小六符合結果。
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "sheng"
}
}
],
"filter": {
"range": {
"age": {
"lte": 25
}
}
}
}
}
}
結果果然不出灑家所料!
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "2",
"_score" : 0.6931472,
"_source" : {
"name" : "大娘子",
"age" : 18,
"from" : "sheng",
"desc" : "膚白貌美,嬌憨可愛",
"tags" : [
"白",
"富",
"美"
]
}
}
]
}
}
但是,灑家手一抖,將must換為should看看會發生什么?
GET zhifou/doc/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"from": "sheng"
}
}
],
"filter": {
"range": {
"age": {
"lte": 25
}
}
}
}
}
}
結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "2",
"_score" : 0.6931472,
"_source" : {
"name" : "大娘子",
"age" : 18,
"from" : "sheng",
"desc" : "膚白貌美,嬌憨可愛",
"tags" : [
"白",
"富",
"美"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "5",
"_score" : 0.0,
"_source" : {
"name" : "魏行首",
"age" : 25,
"from" : "廣雲台",
"desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
"tags" : [
"閉月",
"羞花"
]
}
},
{
"_index" : "zhifou",
"_type" : "doc",
"_id" : "3",
"_score" : 0.0,
"_source" : {
"name" : "龍套偏房",
"age" : 22,
"from" : "gu",
"desc" : "mmp,沒怎么看,不知道怎么形容",
"tags" : [
"造數據",
"真",
"難"
]
}
}
]
}
}
結果有點出乎意料,因為龍套偏房和魏行首不屬於盛家,但也被查詢出來了。那你要問了,怎么肥四?小老弟!這是因為在查詢過程中,優先經過filter過濾,因為should是或關系,龍套偏房和魏行首的年齡符合了filter過濾條件,也就被放行了!所以,如果在filter過濾條件中使用should的話,結果可能不會盡如人意!建議使用must代替。
注意:filter工作於bool查詢內。比如我們將剛才的查詢條件改一下,把filter從bool中挪出來。
GET zhifou/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "sheng"
}
}
]
},
"filter": {
"range": {
"age": {
"lte": 25
}
}
}
}
}
如上例所示,我們將filter與bool平級,看查詢結果:
{
"error": {
"root_cause": [
{
"type": "parsing_exception",
"reason": "[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
"line": 12,
"col": 5
}
],
"type": "parsing_exception",
"reason": "[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
"line": 12,
"col": 5
},
"status": 400
}
結果報錯了!所以,filter工作位置很重要。
小結:
must:與關系,相當於關系型數據庫中的and。should:或關系,相當於關系型數據庫中的or。must_not:非關系,相當於關系型數據庫中的not。filter:過濾條件。range:條件篩選范圍。gt:大於,相當於關系型數據庫中的>。gte:大於等於,相當於關系型數據庫中的>=。lt:小於,相當於關系型數據庫中的<。lte:小於等於,相當於關系型數據庫中的<=。
歡迎斧正,that's all
