ElasticSearch學(xué)習(xí)之多條件組合查詢驗證及示例分析
多條件組合查詢
bool
es
中使用bool
來控制多條件
查詢,bool
查詢支持以下參數(shù):
must
:被查詢的數(shù)據(jù)必須滿足
當(dāng)前條件mush_not
:被查詢的數(shù)據(jù)必須不滿足
當(dāng)前條件should
:被查詢的數(shù)據(jù)應(yīng)該滿足
當(dāng)前條件。should
查詢被用于修正查詢結(jié)果的評分。需要注意的是,如果組合查詢中沒有must
,那么被查詢的數(shù)據(jù)至少要匹配一條should
。如果有must
語句,那么就無須匹配should
,should
將完全用于修正查詢結(jié)果的評分filter
:被查詢的數(shù)據(jù)必須滿足
當(dāng)前條件,但是filter
操作不涉及查詢結(jié)果評分。僅用于條件過濾
下面通過一個例子來看下如何使用:
GET class_1/_search { "query": { "bool": { "must": [ {"match": { "name": "apple" }} ], "must_not": [ {"term": { "num": { "value": "5" } }} ], "should": [ {"match": { "name": "k" }} ],"filter": [ {"range": { "num": { "gte": 0, "lte": 10 } }} ] } } }
結(jié)果返回:
{ "took" : 9, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.752627, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 0.7389809, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } }
constant_score
constant_score
查詢可以通過boost
指定一個固定的評分,通常來說,constant_score
的作用是代替一個只有filter
的bool
查詢
下面看具體使用:
GET class_1/_search { "query": { "constant_score": { "filter": { "term": { "num": 6 } }, "boost": 1.2 } } }
返回:
{ "took" : 7, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 1.2, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : 1.2, "_source" : { "name" : "b", "num" : 6 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_score" : 1.2, "_source" : { "name" : "l", "num" : 6 } } ] } }
查詢驗證 & 分析
驗證
es
中通過/_validate/query
路由來驗證查詢條件的正確性, 這里要注意是驗證查詢條件是否準(zhǔn)確
示例:
GET class_1/_validate/query?explain { "query": { "bool": { "must": [ {"match": { "name": "apple" }} ] } } }
正常返回:
{ "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "valid" : true, "explanations" : [ { "index" : "class_1", "valid" : true, "explanation" : "+name:apple" } ] }
將name
字段改為 name1
再查詢:
{ "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "valid" : true, "explanations" : [ { "index" : "class_1", "valid" : true, "explanation" : """+MatchNoDocsQuery("unmapped fields [name1]")""" } ] }
可以看到報了異常錯誤
分析
es
中通過/_validate/query?explain
路由來進(jìn)行查詢分析
示例:
GET class_1/_validate/query?explain { "query": { "bool": { "must": [ {"match": { "name": "apple so" }} ] } } }
返回:
{ "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "valid" : true, "explanations" : [ { "index" : "class_1", "valid" : true, "explanation" : "+(name:apple name:so)" } ] }
可以看到"explanation" : "+(name:apple name:so)"
,查詢的短語apple so
被進(jìn)行了分詞,分成了name:apple
, name: so
排序
默認(rèn)排序
在前面的幾個例子中,我們可以看到它的默認(rèn)排序是按照_score降序,也就是匹配度高的比較靠前,但是_socre
的計算是很占用查詢性能的,這個不難理解。
當(dāng)我們不需要進(jìn)行_score計算,可以通過filter
或constant_score
來進(jìn)行構(gòu)建查詢條件
filter
示例:
GET class_1/_search { "query": { "bool": { "filter": [ {"term": { "num": 1 }} ] } } }
返回:
{ "took" : 5, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 0.0, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 0.0, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 0.0, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } }
通過查詢結(jié)果我們發(fā)現(xiàn)score
都為0.0
了,說明沒有進(jìn)行score
計算
constant_score
示例:
GET class_1/_search { "query": { "constant_score": { "filter": { "term": { "num": 1 } }, "boost": 1.2 } } }
返回:
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 1.2, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 1.2, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 1.2, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 1.2, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } }
可以看到,對應(yīng)返回的分值,都是使用boost
屬性指定的分值
自定義排序
自定義可以用于大部分場景,那么es
中怎么進(jìn)行自定義排序呢? es
中使用sort
參數(shù)來自定義排序順序,默認(rèn)為升序,那么降序怎么操作呢?
- 升序
{"sort":["num"]}
- 降序,
desc
代表降序
{"sort":[{"num":{"order":"desc"}}]}
tips
es
中使用doc value
列式存儲來實現(xiàn)字段的排序功能text
字段默認(rèn)不創(chuàng)建doc value
,因此無法針對text
字段進(jìn)行排序- 可以通過設(shè)置
text
字段屬性fielddata=true
來開啟對text
字段的排序功能,但是不建議開啟,對text
字段排序及其消耗查詢性能且不符合需求
單字段排序
GET class_1/_search { "sort": [ "num" ] }
返回:
{ "took" : 6, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 11, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : null, "_source" : { "name" : "b", "num" : 6 }, "sort" : [ 6 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_score" : null, "_source" : { "name" : "l", "num" : 6 }, "sort" : [ 6 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : null, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] }, "sort" : [ 9 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "4", "_score" : null, "_source" : { "name" : "f", "age" : 10, "num" : 10 }, "sort" : [ 10 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "RWlfBIUBDuA8yW5cu9wu", "_score" : null, "_source" : { "name" : "一年級", "num" : 20 }, "sort" : [ 20 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iGFt-4UBECmbBdQAnVJe", "_score" : null, "_source" : { "name" : "g", "age" : 8 }, "sort" : [ 9223372036854775807 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iWFt-4UBECmbBdQAnVJg", "_score" : null, "_source" : { "name" : "h", "age" : 9 }, "sort" : [ 9223372036854775807 ] } ] } }
可以看到是按照num
默認(rèn)升序排序
再看下降序:
GET class_1/_search { "sort": [ {"num": {"order":"desc"}} ] }
返回:
{ "took" : 15, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 11, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "RWlfBIUBDuA8yW5cu9wu", "_score" : null, "_source" : { "name" : "一年級", "num" : 20 }, "sort" : [ 20 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "4", "_score" : null, "_source" : { "name" : "f", "age" : 10, "num" : 10 }, "sort" : [ 10 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : null, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] }, "sort" : [ 9 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : null, "_source" : { "name" : "b", "num" : 6 }, "sort" : [ 6 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_score" : null, "_source" : { "name" : "l", "num" : 6 }, "sort" : [ 6 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : null, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 }, "sort" : [ 1 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iGFt-4UBECmbBdQAnVJe", "_score" : null, "_source" : { "name" : "g", "age" : 8 }, "sort" : [ -9223372036854775808 ] }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iWFt-4UBECmbBdQAnVJg", "_score" : null, "_source" : { "name" : "h", "age" : 9 }, "sort" : [ -9223372036854775808 ] } ] } }
這下就降序
排序了
多字段
GET class_1/_search { "sort": [ "num", "age" ] }
scroll分頁
還記得之前給大家講的from+size
的分頁方式嗎,es
中默認(rèn)允許from+size
的分頁的最大數(shù)據(jù)量為10000
。當(dāng)我們想要批量獲取更大的數(shù)據(jù)量時,使用from+size
就會十分的耗費(fèi)性能。
然而大部分應(yīng)用場景下的數(shù)據(jù)量是極其龐大的,比如你要查詢某些系統(tǒng)日志數(shù)據(jù)。es
中可以使用/scorll
路由來進(jìn)行滾動分頁查詢
,它類似于在查詢初始時間點(diǎn)創(chuàng)建了一個當(dāng)前服務(wù)集群的數(shù)據(jù)快照
(包含每一個分片),并保留它一段時間。在時間超過了設(shè)置的過期時間以后,快照將在es空閑時被刪除。
需要注意的是,因為是進(jìn)行快照
查詢,因此在快照
創(chuàng)建后數(shù)據(jù)的變更在本次的滾動查詢中,不可見
初始化快照 & 快照保存10分鐘
查詢示例:
GET class_1/_search?scroll=10m { "query": { "match_phrase": { "name": "apple" } }, "size": 2 }
返回:
{ "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAAXoFjEwWkdOMkxLUTVPZEMzM01ZdHhPc1EAAAAAAAACABZjUy1CemQwQVFfU3BUeGs2OGk0R1Z3AAAAAAAAAgEWY1MtQnpkMEFRX1NwVHhrNjhpNEdWdw==", "took" : 6, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.752627, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } } ] } }
如圖,當(dāng)前共返回2
條數(shù)據(jù),并且返回了一個快照ID,后續(xù)可以根據(jù)快照ID進(jìn)行滾動查詢:
根據(jù)快照ID滾動查詢
GET /_search/scroll { "scroll": "10m", "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAAXoFjEwWkdOMkxLUTVPZEMzM01ZdHhPc1EAAAAAAAACABZjUy1CemQwQVFfU3BUeGs2OGk0R1Z3AAAAAAAAAgEWY1MtQnpkMEFRX1NwVHhrNjhpNEdWdw==" }
返回:
{ "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAAXoFjEwWkdOMkxLUTVPZEMzM01ZdHhPc1EAAAAAAAACABZjUy1CemQwQVFfU3BUeGs2OGk0R1Z3AAAAAAAAAgEWY1MtQnpkMEFRX1NwVHhrNjhpNEdWdw==", "took" : 6, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.752627, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 0.7389809, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } }
在滾動一次:
{ "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAAXoFjEwWkdOMkxLUTVPZEMzM01ZdHhPc1EAAAAAAAACABZjUy1CemQwQVFfU3BUeGs2OGk0R1Z3AAAAAAAAAgEWY1MtQnpkMEFRX1NwVHhrNjhpNEdWdw==", "took" : 1, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.752627, "hits" : [ ] } }
有的小伙伴可能不知道怎么滾動
的,因為后續(xù)滾動都是同一個scroll_id
,其實通過結(jié)果,我們不難發(fā)現(xiàn):
- 首先創(chuàng)建了一個10分鐘的
快照
,規(guī)定了每次返回的數(shù)據(jù)量為2條
,并且初始化的時候,返回了2條 - 通過
scroll_id
進(jìn)行滾動操作,返回了1條
數(shù)據(jù),原因是快照的數(shù)據(jù)量總共只有3條
,初始化的時候返回了2條
,所以現(xiàn)在只有1條
- 再次滾動的時候,發(fā)現(xiàn)返回了空,因為數(shù)據(jù)已經(jīng)被查完了
以上就是ElasticSearch 多條件組合查詢驗證及示例分析的詳細(xì)內(nèi)容,更多關(guān)于ElasticSearch 多條件組合查詢的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot實現(xiàn)elasticsearch 查詢操作(RestHighLevelClient 
這篇文章主要給大家介紹了SpringBoot如何實現(xiàn)elasticsearch 查詢操作,文中有詳細(xì)的代碼示例和操作流程,具有一定的參考價值,需要的朋友可以參考下2023-07-07詳解JavaScript中的函數(shù)聲明和函數(shù)表達(dá)式
這篇文章主要介紹了詳解JavaScript中的函數(shù)聲明和函數(shù)表達(dá)式,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08Java如何使用ReentrantLock實現(xiàn)長輪詢
這篇文章主要介紹了如何使用ReentrantLock實現(xiàn)長輪詢,對ReentrantLock感興趣的同學(xué),可以參考下2021-04-04Spring?Security實現(xiàn)統(tǒng)一登錄與權(quán)限控制的示例代碼
這篇文章主要介紹了Spring?Security實現(xiàn)統(tǒng)一登錄與權(quán)限控制,本文通過示例代碼重點(diǎn)看一下統(tǒng)一認(rèn)證中心和業(yè)務(wù)網(wǎng)關(guān)的建設(shè),需要的朋友可以參考下2022-03-03Spring整合CXF webservice restful實例詳解
這篇文章主要為大家詳細(xì)介紹了Spring整合CXF webservice restful的實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08關(guān)于Java中@SuppressWarnings的正確使用方法
這篇文章主要介紹了關(guān)于Java中@SuppressWarnings的正確使用方法,@SuppressWarnings注解主要用在取消一些編譯器產(chǎn)生的警告對代碼左側(cè)行列的遮擋,有時候這會擋住我們斷點(diǎn)調(diào)試時打的斷點(diǎn),需要的朋友可以參考下2023-05-05