1.概述
Elasticsearch主要的查詢語法包括URI查詢和body查詢结洼,URI比較輕便快速僻弹,而body查詢作為一種json的格式化查詢,可以有許多限制條件并炮。本文主要介紹結(jié)構(gòu)化查詢的query默刚,filter,aggregate的使用逃魄,本文使用的ES版本為6.5.4荤西,中文分詞器使用的ik,安裝和使用可以參考:
Elasticsearch 安裝和使用
Elasticsearch中ik分詞器的使用
在ES建立以下索引伍俘,并且導(dǎo)入數(shù)據(jù)
PUT /news
{
"aliases": {
"news": {}
},
"mappings":{
"news": {
"dynamic": "false",
"properties": {
"id": {
"type": "integer"
},
"title": {
"analyzer": "ik_max_word",
"type": "text"
},
"summary": {
"analyzer": "ik_max_word",
"type": "text"
},
"author": {
"type": "keyword"
},
"publishTime": {
"type": "date"
},
"modifiedTime": {
"type": "date"
},
"createTime": {
"type": "date"
},
"docId": {
"type": "keyword"
},
"voteCount": {
"type": "integer"
},
"replyCount": {
"type": "integer"
}
}
}
},
"settings":{
"index": {
"refresh_interval": "1s",
"number_of_shards": 3,
"max_result_window": "10000000",
"mapper": {
"dynamic": "false"
},
"number_of_replicas": 1
}
}
}
}
}
2.查詢
2.1 一個查詢的例子
一個簡單的查詢例子如下邪锌,查詢主要分為query和filter,這兩種類型的查詢結(jié)構(gòu)都在query里面癌瘾,剩下的sort標(biāo)識排序觅丰,size和from用來翻頁,_source用來指定召回document返回哪些字段妨退。
查詢請求:
GET /news/_search
{
"query": {"match_all": {}},
"sort": [
{
"publishTime": {
"order": "desc"
}
}
],
"size": 2,
"from": 0,
"_source": ["title", "id", "summary"]
}
返回結(jié)果:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 204,
"max_score" : null,
"hits" : [
{
"_index" : "news",
"_type" : "news",
"_id" : "228",
"_score" : null,
"_source" : {
"summary" : "據(jù)陜西高院消息妇萄,6月11日上午,西安市中級人民法院二審公開開庭宣判了陜西省首例“套路貸”涉黑案件——韓某某等人非法放貸一案咬荷,法院駁回上訴冠句,維持原判。西安市中級人",
"id" : 228,
"title" : "陜西首例套路貸涉黑案宣判:團伙對借款人噴辣椒水"
},
"sort" : [
1560245097000
]
},
{
"_index" : "news",
"_type" : "news",
"_id" : "214",
"_score" : null,
"_source" : {
"summary" : "網(wǎng)易娛樂6月11日報道6月11日幸乒,有八卦媒體曝光曹云金與妻子唐菀現(xiàn)身天津民政局辦理了離婚手續(xù)懦底。對此,網(wǎng)易娛樂向曹云金經(jīng)紀(jì)人求證罕扎,得到了對方獨家回應(yīng):“確實是離婚",
"id" : 214,
"title" : "曹云金承認已離婚:和平離婚 有人惡意中傷心思歹毒"
},
"sort" : [
1560244657000
]
}
]
}
}
返回結(jié)果中took表示耗時聚唐,_shards表示分片信息,當(dāng)前index有3個分片腔召,并且3個分片都工作正常杆查,hits表示命中的結(jié)果,total表示命中總數(shù)宴咧,max_score表示最大的分值根灯,hits表示命中的具體document。
查詢分為精確過濾(filter)和全文搜索(query)兩種:精確過濾容易被緩存掺栅,因此它的執(zhí)行速度非忱臃危快。
2.2 Filter
2.2.1 term
term 查找可以精確的找到符合條件的記錄氧卧,其中的FIELD標(biāo)識索引中的字段桃笙,VALUE表示需要查詢的值∩尘基本的查詢語句如下:
{
"term": {
"FIELD": {
"value": "VALUE"
}
}
}
比如搏明,查詢source為中新經(jīng)緯的新聞,那么可以這么使用:
GET /news/_search
{
"query": {"term": {
"source": {
"value": "中新經(jīng)緯"
}
}}
}
2.2.2 bool
當(dāng)需要多個邏輯組合查詢的時候闪檬,可以使用bool來組各邏輯星著。bool可以包含
{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
must:搜索的結(jié)果必須匹配,類似SQL的AND
must_not: 搜索的結(jié)果必須不匹配粗悯,類似SQL的NOT
should: 搜索的結(jié)果至少匹配到一個虚循,類似SQL的OR
當(dāng)我們需要查source為中新經(jīng)緯,并且id為4或者75的新聞样傍,可以這樣使用:
GET /news/_search
{
"query": {
"bool": {
"must": [
{"term": {
"source": {
"value": "中新經(jīng)緯"
}
}}
],
"should": [
{"term": {
"id": {
"value": "4"
}
}},
{"term": {
"id": {
"value": "75"
}
}}
],
"minimum_should_match": 1
}}
}
其中的minimun_should_match用來指定should內(nèi)的條件需要匹配多少個横缔,默認是0,0的情況下should內(nèi)容只參與打分衫哥,不做倒排過濾茎刚。
2.2.3 terms
對于上面查找多個精確值的情況,可以使用terms撤逢,比如查找id是4或者75的文章膛锭,可以這么使用:
GET /news/_search
{
"query": {"terms": {
"id": [
"4",
"75"
]
}}
}
2.2.4 range
對于需要用到范圍的查詢,可以使用range蚊荣,range和term作用的位置相同初狰,比如查找id從1到10的文章
GET /news/_search
{
"query": {"range": {
"id": {
"gte": 1,
"lte": 10
}
}}
}
其中:
- gt: > 大于(greater than)
- lt: < 小于(less than)
- gte: >= 大于或等于(greater than or equal to)
- lte: <= 小于或等于(less than or equal to)
2.2.5 exists
es中可以使用exists來查找某個字段存在或者不存在的document,比如查找存在author字段的文檔妇押,也可以在bool內(nèi)配合should和must_not使用跷究,就可以實現(xiàn)不存在或者可能存在的查詢。
GET /news/_search
{
"query": {
"exists": {"field": "author"}
}
}
2.3 Query
和filter的精確匹配不一樣敲霍,query可以進行一些字段的全文搜索和搜索結(jié)果打分俊马,es中只有類型為text的字段才可以被分詞,類型為keyword雖然也是字符串肩杈,但只能作為枚舉柴我,不能被分詞,text的分詞類型可以在創(chuàng)建索引的時候指定扩然。
2.3.1 match
當(dāng)我們想要搜某個字段的時候可以使用match艘儒,比如查找文章中出現(xiàn)體育的新聞,可以這樣查詢
GET /news/_search
{
"query": {
"match": {"summary":"體育" }
}
}
在match中我們還可以指定分詞器,比如指定分詞器為ik_smart對輸入的詞盡量分大顆粒界睁,此時召回的就是含有進口紅酒的document觉增,如果指定分詞器為ik_max_word則分出的詞顆粒會比較小,會召回包含口紅和紅酒的document
{
"match": {
"name": {
"query": "進口紅酒",
"analyzer": "ik_smart"
}
}
}
對于query的文本有可能分出好幾個詞翻斟,這個時候可以用and連接逾礁,表示多個詞都命中才被召回,如果用or連接访惜,則類似should可以控制嘹履,至少命中多少個詞才被召回。比如搜索包含體育新聞內(nèi)容的新聞债热,下面這個查詢只要包含一個體育或者新聞的document都會被召回
GET /news/_search
{
"query": {
"match": {
"summary": {
"query": "體育新聞",
"operator": "or",
"minimum_should_match": 1
}
}
}
}
2.3.2 multi_match
當(dāng)需要搜索多個字段的時候砾嫉,可以使用multi_match進行查詢,比如在title或者summary中搜索含有新聞關(guān)鍵詞的document
GET /news/_search
{
"query": {
"multi_match": {
"query": "新聞",
"fields": ["title", "summary"]
}
}
}
2.4 組合查詢
有了全文搜索和過濾的這些字段窒篱,配合bool就可以實現(xiàn)復(fù)雜的組合查詢
GET /news/_search
{
"query": {"bool": {
"must": [
{"match": {
"summary": {
"boost": 1,
"query": "長安"
}
}
},
{
"term": {
"source": {
"value": "中新經(jīng)緯",
"boost": 2
}
}
}
],
"filter": {"bool": {
"must":[
{"term":{
"id":75
}}
]
}}
}}
}
上面請求bool中的must焕刮、must_not、should可以使用term舌剂,range济锄、match。這些默認都是參與打分的霍转,可以通過boost來控制打分的權(quán)重荐绝,如果不想要某些查詢條件參與打分,可以在bool中添加filter避消,這個filter中的查詢字段都不參與打分低滩,而且查詢的內(nèi)容可以被緩存。
3.聚合
聚合的基本格式為:
GET /news/_search
{
"size": 0,
"aggs": {
"NAME": {
"AGG_TYPE": {}
}
}
}
其中NAME表示當(dāng)前聚合的名字岩喷,可以取任意合法的字符串恕沫,AGG_TYPE表示聚合的類型,常見的為分為多值聚合和單值聚合
3.1 一個聚合的例子
GET /news/_search
{
"size": 0,
"aggs": {
"sum_all": {
"sum": {
"field": "replyCount"
}
}
}
}
上面的例子表示查詢當(dāng)前庫里面的replayCount的和纱意,返回結(jié)果:
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 204,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"sum_all" : {
"value" : 390011.0
}
}
}
返回結(jié)果中默認會包含命中的document婶溯,所以需要把size指定為0,結(jié)果中的sum_all為請求中指定的名字偷霉。
Elasticsearch中的聚合類型主要分為Metrics和Bucket
3.2 Metrics
metrics主要是一些單值的返回迄委,像avg、max类少、min叙身、sum、stats等這些計算硫狞。
3.2.1 max
比如計算index里面最多的點贊數(shù)是多少信轿,可以這樣使用晃痴,max、avg财忽、min倘核、sum使用類似
GET /news/_search
{
"size": 0,
"aggs": {
"max_replay": {
"max": {
"field": "replyCount"
}
}
}
}
3.2.2 stats
常用的一些統(tǒng)計信息,可以用stats定罢,比如查看某個字段的笤虫,總數(shù)旁瘫,最小值祖凫,最大值,平均值等酬凳,比如查看document中新聞回復(fù)量的基本情況惠况,stats就是統(tǒng)計的綜合使用。比如請求如下:
GET /news/_search
{
"size": 0,
"aggs": {
"cate": {
"stats": {
"field": "replyCount"
}
}
}
}
返回結(jié)果為:
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 204,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"cate" : {
"count" : 202,
"min" : 0.0,
"max" : 32534.0,
"avg" : 1930.7475247524753,
"sum" : 390011.0
}
}
}```
能返回基本的統(tǒng)計信息
3.3 Bucket
桶類似于sql里面的group by宁仔,使用Bucket會對內(nèi)容進行分桶
3.3.1 terms
利用terms分桶之后稠屠,可以查看數(shù)據(jù)的分布,比如可以查看index中一共有多少個source翎苫,每個source有多少文章权埠,size是用來指定返回最多的幾個分類,可以這樣使用:
GET /test_ratings_v1/_search
{
"size": 0,
"aggs": {
"myterms": {
"terms": {
"field": "productId",
"size": 10
}
}
}
}
表示對productId進行分桶煎谍,返回每個桶的個數(shù)攘蔽。外層的size表示不返回命中的數(shù)據(jù),只返回聚合結(jié)果
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 10002,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"myterms" : {
"doc_count_error_upper_bound" : 69,
"sum_other_doc_count" : 5701,
"buckets" : [
{
"key" : 452966,
"doc_count" : 1168
},
{
"key" : 452734,
"doc_count" : 608
},
{
"key" : 453353,
"doc_count" : 592
},
{
"key" : 453231,
"doc_count" : 522
},
{
"key" : 453275,
"doc_count" : 387
},
{
"key" : 452639,
"doc_count" : 273
},
{
"key" : 453104,
"doc_count" : 236
},
{
"key" : 452679,
"doc_count" : 180
},
{
"key" : 453152,
"doc_count" : 169
},
{
"key" : 452640,
"doc_count" : 165
}
]
}
}
}
返回結(jié)果key表示productId呐粘,doc_count表示數(shù)目
3.3.2 range
除了按值進行聚合满俗,還可以按范圍進行聚合,比如作岖,求rating的值3-4和小于3唆垃,大于4的統(tǒng)計,可以這樣寫
{
"size": 0,
"aggs": {
"myterms": {
"range": {
"field": "rating",
"ranges": [
{
"from": 3,
"to": 4
},
{
"from": 4
},
{
"to":3
}
]
}
}
}
}
得到返回結(jié)果:
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 10002,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"myterms" : {
"buckets" : [
{
"key" : "*-3.0",
"to" : 3.0,
"doc_count" : 1101
},
{
"key" : "3.0-4.0",
"from" : 3.0,
"to" : 4.0,
"doc_count" : 1464
},
{
"key" : "4.0-*",
"from" : 4.0,
"doc_count" : 7436
}
]
}
}
}
可以看到小于3的有1101個痘儡,3-4的有1464個辕万,而大于4的有7436個。
3.4 組合聚類
GET /news/_search
{
"size": 0,
"aggs": {
"myterms": {
"terms": {
"field": "source",
"size": 100
},
"aggs": {
"replay": {
"terms": {
"field": "replyCount",
"size": 10
}
},
"avg_price": {
"avg": {
"field": "voteCount"
}
}
}
}
}
}
上面代碼首先對source分桶沉删,在每個souce類型里面在對replayCount進行分桶渐尿,并且計算每個source類里面的voteCount的平均值
由于返回結(jié)果比較大,這里只給出返回的某一個桶結(jié)果:
{
"key" : "中國新聞網(wǎng)",
"doc_count" : 16,
"avg_price" : {
"value" : 1195.0
},
"replay" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 4,
"buckets" : [
{
"key" : 0,
"doc_count" : 3
},
{
"key" : 1,
"doc_count" : 1
},
{
"key" : 5,
"doc_count" : 1
},
{
"key" : 32,
"doc_count" : 1
},
{
"key" : 97,
"doc_count" : 1
},
{
"key" : 106,
"doc_count" : 1
},
{
"key" : 133,
"doc_count" : 1
},
{
"key" : 155,
"doc_count" : 1
},
{
"key" : 156,
"doc_count" : 1
},
{
"key" : 248,
"doc_count" : 1
}
]
}
}
4.查詢和聚合的組合使用
有了查詢和聚合丑念,我們就可以對查詢的結(jié)果做聚合涡戳,比如我想查看summary中包含體育的新聞都是那些來源網(wǎng)站,就可以像下面這樣查詢:
GET /news/_search
{
"size": 0,
"query": {"bool": {"must": [
{"match": {
"summary": "體育"
}}
]}},
"aggs": {
"cate": {
"terms": {
"field": "source"
}
}
}
}
5.總結(jié)
Elasticsearch的查詢語法比較復(fù)雜和多樣脯倚,這里只例舉了常見的一些查詢和聚合渔彰,詳細可以參考官方文檔和權(quán)威指南嵌屎,權(quán)威指南由于是中文,閱讀比較方便恍涂,但是是2.x的內(nèi)容宝惰,官方文檔有對應(yīng)版本的內(nèi)容,內(nèi)容比較新再沧,建議閱讀官方文檔尼夺。
Elasticsearch權(quán)威指南(中文)
Elasticsearch6.5 官方文檔(英文)
更多精彩內(nèi)容,請關(guān)注公眾號