https://www.cnblogs.com/sunsky303/p/9443013.html
由於筆者在實際項目僅僅將ES用作索引數據庫,並沒有深入研究過ES的搜索功能。而且鑑於筆者的搜索引擎知識有限,本文將僅僅介紹ES簡單(非全文)的查詢API。
筆者原本打算在本文中介紹聚合API的內容,但是寫着寫着發現文章有點過長,不便於閱讀,故將聚合API的內容移至下一篇博客中。
引言
單單介紹理論和API是乏味和低效率的,本文將結合一個實際的例子來介紹這些API。下表是本文數據表的表結構,表名(type)爲“student”。注意,studentNo是本表的id,也就是_id字段的值與studentNo的值保持一致。
字段名 | 字段含義 | 類型 | 是否能被索引 | 備註 |
---|---|---|---|---|
studentNo | 學號 | string | 是 | id |
name | 姓名 | string | 是 | |
sex | 性別 | string | 是 | |
age | 年齡 | integer | 是 | |
birthday | 出生年月 | date | 是 | |
address | 家庭住址 | string | 是 | |
classNo | 班級 | string | 是 | |
isLeader | 是否爲班幹部 | boolean | 是 |
上面的表結構所對應的mapping如下,將數據保存在索引名爲“student”的索引中。
{
"student": {
"properties": {
"studentNo": {
"type": "string",
"index": "not_analyzed"
},
"name": {
"type": "string",
"index": "not_analyzed"
},
"male": {
"type": "string",
"index": "not_analyzed"
},
"age": {
"type": "integer"
},
"birthday": {
"type": "date",
"format": "yyyy-MM-dd"
},
"address": {
"type": "string",
"index": "not_analyzed"
},
"classNo": {
"type": "string",
"index": "not_analyzed "
},
"isLeader": {
"type": "boolean"
}
}
}
}
索引中保存的數據如下,下面介紹的所有API都將基於這個數據表。
studentNo | name | male | age | birthday | classNo | address | isLeader |
---|---|---|---|---|---|---|---|
1 | 劉備 | 男 | 24 | 1985-02-03 | 1 | 湖南省長沙市 | true |
2 | 關羽 | 男 | 22 | 1987-08-23 | 2 | 四川省成都市 | false |
3 | 糜夫人 | 女 | 19 | 1990-06-12 | 1 | 上海市 | false |
4 | 張飛 | 男 | 20 | 1989-07-30 | 3 | 北京市 | false |
5 | 諸葛亮 | 男 | 18 | 1992-04-27 | 2 | 江蘇省南京市 | true |
6 | 孫尚香 | 女 | 16 | 1994-05-21 | 3 | false | |
7 | 馬超 | 男 | 19 | 1991-10-20 | 1 | 黑龍江省哈爾濱市 | false |
8 | 趙雲 | 男 | 23 | 1986-10-26 | 2 | 浙江省杭州市 | false |
查詢API
ES中的查詢非常靈活,爲用戶提供了非常方便而強大的API。個人覺得ES的調用接口設計得非常好,所有接口合理且風格一致,值得好好研究!
Query和Filter
ES爲用戶提供兩類查詢API,一類是在查詢階段就進行條件過濾的query查詢,另一類是在query查詢出來的數據基礎上再進行過濾的filter查詢。這兩類查詢的區別是:
- query方法會計算查詢條件與待查詢數據之間的相關性,計算結果寫入一個score字段,類似於搜索引擎。filter僅僅做字符串匹配,不會計算相關性,類似於一般的數據查詢,所以filter得查詢速度比query快。
- filter查詢出來的數據會自動被緩存,而query不能。
query和filter可以單獨使用,也可以相互嵌套使用,非常靈活。
Query查詢
下面的情況下適合使用query查詢:
- 需要進行全文搜索。
- 查詢結果依賴於相關性,即需要計算查詢串和數據的相關性。
(1)Match All Query
查詢所有的數據,相當於不帶條件查詢。下面的代碼是一個典型的match_all查詢的調用方式。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"match_all": {}
}
}
'
查詢結果如下。其他所有的查詢都是返回這種格式的數據。
{
"took": 156, // 查詢耗時(毫秒)
"timed_out": false, // 是否超時
"_shards": {
"total": 5, // 總共查詢的分片數
"successful": 5, // 查詢成功的分片數
"failed": 0 // 查詢失敗的分片數
},
"hits": {
"total": 8, // 本次查詢的記錄數
"max_score": 1, // 查詢所有數據中的最大score
"hits": [ // 數據列表
{
"_index": "student", // 數據所屬的索引名
"_type": "student", // 數據所屬的type
"_id": "4", // 數據的id值
"_score": 1, // 該記錄的score
"_source": { // ES將原始數據保存到_source字段中
"studentNo": "4",
"name": "張飛",
"male": "男",
"age": "20",
"birthday": "1989-07-30",
"classNo": "3",
"isLeader": "F"
}
},
{
…… // 其他的數據格式相同,就不列出來了
}
]
}
}
查詢時,你會發現無論數據量有多大,每次最多隻能查到10條數據。這是因爲ES服務端默認對查詢結果做了分頁處理,每頁默認的大小爲10。如果想自己指定查詢的數據,可使用from和size字段,並且按指定的字段排序。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"match_all": {}
},
"from": 2, // 從2條記錄開始取
"size": 4, // 取4條數據
"sort": {
"studentNo": { // 按studentNo字段升序
"order": "asc"// 降序爲desc
}
}
}
'
注意:不要把from設得過大(超過10000),否則會導致ES服務端因頻繁GC而無法正常提供服務。其實實際項目中也沒有誰會翻那麼多頁,但是爲了ES的可用性,務必要對分頁查詢的頁碼做一定的限制。
(2)term query
詞語查詢,如果是對未分詞的字段進行查詢,則表示精確查詢。查找名爲“諸葛亮”的學生,查詢結果爲學號爲5的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"term": {
"name": "諸葛亮"
}
}
}
'
(3)Bool Query
Bool(布爾)查詢是一種複合型查詢,它可以結合多個其他的查詢條件。主要有3類邏輯查詢:
- must:查詢結果必須符合該查詢條件(列表)。
- should:類似於in的查詢條件。如果bool查詢中不包含must查詢,那麼should默認表示必須符合查詢列表中的一個或多個查詢條件。
- must_not:查詢結果必須不符合查詢條件(列表)。
查找2班的班幹部,查詢結果爲學號爲5的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"bool": {
"must": [
{
"term": {
"classNo": "2"
}
},
{
"term": {
"isLeader": "true"
}
}
]
}
}
}
'
(4)Ids Query
id字段查詢。查詢數據id值爲1和2的同學,由於id的值與studentNo相同,故查詢結果爲學號爲1和2的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"ids": {
"type": "student",
"values": [
"1",
"2"
]
}
}
}
'
(5)Prefix Query
前綴查詢。查找姓【趙】的同學,查詢結果是學號爲8的趙雲。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"prefix": {
"name": "趙"
}
}
}
'
(6)Range Query
範圍查詢,針對date和number類型的數據。查找年齡到18~20歲的同學,查詢結果是學號爲3、4、5、7的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"range": {
"age": {
"gte": "18", // 表示>=
"lte": "20" // 表示<=
}
}
}
}
'
實際上,對於date類型的數據,ES中以其時間戳(長整形)的形式存放的。
(7)Terms Query
多詞語查詢,查找符合詞語列表的數據。如果要查詢的字段索引爲not_analyzed類型,則terms查詢非常類似於關係型數據庫中的in查詢。下面查找學號爲1,3的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"terms": {
"studentNo": [
"1",
"3"
]
}
}
}
'
(8)Wildcard Query
通配符查詢,是簡化的正則表達式查詢,包括下面兩類通配符:
- * 代表任意(包括0個)多個字符
- ? 代表任意一個字符
查找名字的最後一個字是“亮”的同學,查詢結果是學號爲5的諸葛亮。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"wildcard": {
"name": "*亮"
}
}
}
'
(9)Regexp Query同學
正則表達式查詢,這是最靈活的字符串類型字段查詢方式。查找家住長沙市的學生,查詢結果爲學號爲1的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": {
"regexp": {
"address": ".*長沙市.*" // 這裏的.號表示任意一個字符
}
}
}
'
Filter查詢
下面的情況下適合使用filter查詢:
- yes/no的二元查詢
- 針對精確值進行查詢
filter和query的查詢方式有不少是重疊的,所以本節僅僅介紹API的調用,一些通用的注意的事項就不再重複了。
(1)Term Filter
詞語查詢,如果是對未分詞的字段進行查詢,則表示精確查詢。查找名爲“諸葛亮”的學生,查詢結果爲學號爲5的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"term": {
"name": "諸葛亮",
"_cache" : true // 與query主要是這裏的區別,可以設置數據緩存
}
}
}
'
filter查詢方式都可以通過設置_cache爲true來緩存數據。如果下一次恰好以相同的查詢條件進行查詢並且該緩存沒有過期,就可以直接從緩存中讀取數據,這樣就大大加快的查詢速度。
(2)Bool Filter
查找2班的班幹部,查詢結果爲學號爲5的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"bool": {
"must": [
{
"term": {
"classNo": "2"
}
},
{
"term": {
"isLeader": "true"
}
}
]
}
}
}
'
(3)And Filter
And邏輯連接查詢,連接1個或1個以上查詢條件。它與bool查詢中的must查詢非常相似。實際上,and查詢可以轉化爲對應的bool查詢。查找2班的班幹部,查詢結果爲學號爲5的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"and": [
{
"term": {
"classNo": "2"
}
},
{
"term": {
"isLeader": "true"
}
}
]
}
}
'
(4)Or Filter
Or連接查詢,表示邏輯或。。查找2班或者是班幹部的學生名單,查詢結果爲學號爲1、2、5、8的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"or": [
{
"term": {
"classNo": "2"
}
},
{
"term": {
"isLeader": "true"
}
}
]
}
}
'
(5)Exists Filter
存在查詢,查詢指定字段至少包含一個非null值的數據。如果字段索引爲not_analyzed類型,則查詢sql中的is not null查詢方式。查詢地址存在學生,查詢結果爲除了6之外的所有學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"exists": {
"field": "address"
}
}
}
'
(6)Missing Filter
缺失值查詢,與Exists查詢正好相反。查詢地址不存在的學生,查詢結果爲學號爲6的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"missing": {
"field": "address"
}
}
}
'
(7)Prefix Filter
前綴查詢。查找姓【趙】的同學,查詢結果是學號爲8的趙雲。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"prefix": {
"name": "趙"
}
}
}
'
(8)Range Filter
範圍查詢,針對date和number類型的數據。查找年齡到18~20歲的同學,查詢結果是學號爲3、4、5、7的記錄。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"range": {
"age": {
"gte": "18",
"lte": "20"
}
}
}
}
'
(9)Terms Filter
多詞語查詢,查找符合詞語列表的數據。如果要查詢的字段索引爲not_analyzed類型,則terms查詢非常類似於關係型數據庫中的in查詢。下面查找學號爲1,3的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"terms": {
"studentNo": [
"1",
"3"
]
}
}
}
'
(10)Regexp Filter
正則表達式查詢,是最靈活的字符串類型字段查詢方式。查找家住長沙市的學生,查詢結果爲學號爲1的學生。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"filter": {
"regexp": {
"address": ".*長沙市.*"
}
}
}
'
Aggregations (聚合)API的使用
ES提供的聚合功能可以用來進行簡單的數據分析。本文仍然以上一篇提供的數據爲例來講解。數據如下:
studentNo | name | male | age | birthday | classNo | address | isLeader |
---|---|---|---|---|---|---|---|
1 | 劉備 | 男 | 24 | 1985-02-03 | 1 | 湖南省長沙市 | true |
2 | 關羽 | 男 | 22 | 1987-08-23 | 2 | 四川省成都市 | false |
3 | 糜夫人 | 女 | 19 | 1990-06-12 | 1 | 上海市 | false |
4 | 張飛 | 男 | 20 | 1989-07-30 | 3 | 北京市 | false |
5 | 諸葛亮 | 男 | 18 | 1992-04-27 | 2 | 江蘇省南京市 | true |
6 | 孫尚香 | 女 | 16 | 1994-05-21 | 3 | false | |
7 | 馬超 | 男 | 19 | 1991-10-20 | 1 | 黑龍江省哈爾濱市 | false |
8 | 趙雲 | 男 | 23 | 1986-10-26 | 2 | 浙江省杭州市 | false |
本文的主要內容有:
- metric API的使用
- bucketing API的使用
- 兩類API的嵌套使用
1. 聚合API
ES中的Aggregations API是從Facets功能基礎上發展而來,官網正在進行替換計劃,建議用戶使用Aggregations API,而不是Facets API。ES中的聚合上可以分爲下面兩類:
- metric(度量)聚合:度量類型聚合主要針對的number類型的數據,需要ES做比較多的計算工作
- bucketing(桶)聚合:劃分不同的“桶”,將數據分配到不同的“桶”裏。非常類似sql中的group語句的含義。
metric既可以作用在整個數據集上,也可以作爲bucketing的子聚合作用在每一個“桶”中的數據集上。當然,我們可以把整個數據集合看做一個大“桶”,所有的數據都分配到這個大“桶”中。
ES中的聚合API的調用格式如下:
"aggregations" : { // 表示聚合操作,可以使用aggs替代
"<aggregation_name>" : { // 聚合名,可以是任意的字符串。用做響應的key,便於快速取得正確的響應數據。
"<aggregation_type>" : { // 聚合類別,就是各種類型的聚合,如min等
<aggregation_body> // 聚合體,不同的聚合有不同的body
}
[,"aggregations" : { [<sub_aggregation>]+ } ]? // 嵌套的子聚合,可以有0或多個
}
[,"<aggregation_name_2>" : { ... } ]* // 另外的聚合,可以有0或多個
}
1.1 度量類型(metric)聚合
(1)Min Aggregation
最小值查詢,作用於number類型字段上。查詢2班最小的年齡值。
curl -XPOST "192.168.1.101:9200/student/student/_search" -d
'
{
"query": { // 可以先使用query查詢得到需要的數據集
"term": {
"classNo": "2"
}
},
"aggs": {
"min_age": {
"min": {
"field": "age"
}
}
}
}
'
查詢結果爲:
{
"took": 19, // 前面部分數據與普通的查詢數據相同
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1.4054651,
"hits": [
{
"_index": "student",
"_type": "student",
"_id": "2",
"_score": 1.4054651,
"_source": {
"studentNo": "2",
"name": "關羽",
"male": "男",
"age": "22",
"birthday": "1987-08-23",
"classNo": "2",
"isLeader": "false"
}
},
{
"_index": "student",
"_type": "student",
"_id": "8",
"_score": 1,
"_source": {
"studentNo": "8",
"name": "趙雲",
"male": "男",
"age": "23",
"birthday": "1986-10-26",
"classNo": "2",
"isLeader": "false"
}
},
{
"_index": "student",
"_type": "student",
"_id": "5",
"_score": 0.30685282,
"_source": {
"studentNo": "5",
"name": "諸葛亮",
"male": "男",
"age": "18",
"birthday": "1992-04-27",
"classNo": "2",
"isLeader": "true"
}
}
]
},
"aggregations": { // 聚合結果
"min_age": { // 前面輸入的聚合名
"value": 18, // 聚合後的數據
"value_as_string": "18.0"
}
}
}
上面的聚合查詢有兩個要注意的點:
- 可以通過query先過濾數據
- 返回的結果會包含聚合操作所作用的數據全集
有時候我們對作用的數據全集並不太敢興趣,我們僅僅需要最終的聚合結果。可以通過查詢類型(search_type)參數來實現這個需求。下面查詢出來的數據量會大大減少,ES內部也會在查詢時減少一些耗時的步驟,所以查詢效率會提高。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d // 注意這裏的search_type=count
'
{
"query": { // 可以先使用query查詢得到需要的數據集
"term": {
"classNo": "2"
}
},
"aggs": {
"min_age": {
"min": {
"field": "age"
}
}
}
}
'
本次的查詢結果爲:
{
...
"aggregations": { // 聚合結果
"min_age": { // 前面輸入的聚合名
"value": 18, // 聚合後的數據
"value_as_string": "18.0"
}
}
}
(2)Max Aggregation
最大值查詢。下面查詢2班最大的年齡值,查詢結果爲23。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"query": {
"term": {
"classNo": "2"
}
},
"aggs": {
"max_age": {
"max": {
"field": "age"
}
}
}
}
'
(3)Sum Aggregation
數值求和。下面統計查詢2班的年齡總和,查詢結果爲63。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"query": {
"term": {
"classNo": "2"
}
},
"aggs": {
"sum_age": {
"sum": {
"field": "age"
}
}
}
}
'
(4)Avg Aggregation
計算平均值。下面計算查詢2班的年齡平均值,結果爲21。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"query": {
"term": {
"classNo": "2"
}
},
"aggs": {
"avg_age": {
"avg": {
"field": "age"
}
}
}
}
'
(5)Stats Aggregation
統計查詢,一次性統計出某個字段上的常用統計值。下面對整個學校的學生進行簡單地統計。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"stats_age": {
"stats": {
"field": "age"
}
}
}
}
'
查詢結果爲:
{
... // 次要數據省略
"aggregations": {
"stats_age": {
"count": 8, // 含有年齡數據的學生計數
"min": 16, // 年齡最小值
"max": 24, // 年齡最大值
"avg": 20.125, // 年齡平均值
"sum": 161, // 年齡總和
"min_as_string": "16.0",
"max_as_string": "24.0",
"avg_as_string": "20.125",
"sum_as_string": "161.0"
}
}
}
(6)Top hits Aggregation
取符合條件的前n條數據記錄。下面查詢全校年齡排在前2位的學生,僅需返回學生姓名和年齡。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
{
"aggs": {
"top_age": {
"top_hits": {
"sort": [ // 排序
{
"age": { // 按年齡降序
"order": "desc"
}
}
],
"_source": {
"include": [ // 指定返回字段
"name",
"age"
]
},
"size": 2 // 取前2條數據
}
}
}
}
返回結果爲:
{
...
"aggregations": {
"top_age": {
"hits": {
"total": 9,
"max_score": null,
"hits": [
{
"_index": "student",
"_type": "student",
"_id": "1",
"_score": null,
"_source": {
"name": "劉備",
"age": "24"
},
"sort": [
24
]
},
{
"_index": "student",
"_type": "student",
"_id": "8",
"_score": null,
"_source": {
"name": "趙雲",
"age": "23"
},
"sort": [
23
]
}
]
}
}
}
}
1.2 桶類型(bucketing)聚合
(1)Terms Aggregation
按照指定的1或多個字段將數據劃分成若干個小的區間,計算落在每一個區間上記錄數量,並按指定順序進行排序。下面統計每個班的學生數,並按學生數從大到小排序,取學生數靠前的2個班級。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"terms_classNo": {
"terms": {
"field": "classNo", // 按照班號進行分組
"order": { // 按學生數從大到小排序
"_count": "desc"
},
"size": 2 // 取前兩名
}
}
}
}
'
值得注意的,取得的前2名的學生數實際上是一個近似值,ES的實現方式參見這裏。如果想要取得精確值,可以不指定size值,使其進行一次全排序,然後在程序中自行去取前2條記錄。當然,這樣做會使得ES做大量的排序運算工作,效率比較差。
(2)Range Aggregation
自定義區間範圍的聚合,我們可以自己手動地劃分區間,ES會根據劃分出來的區間將數據分配不同的區間上去。下面將全校學生按照年齡劃分爲5個區間段:16歲以下、16~18、19~21、22~24、24歲以上,要求統計每一個年齡段內的學生數。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"range_age": {
"range": {
"field": "age",
"ranges": [
{
"to": 15
},
{
"from": "16",
"to": "18"
},
{
"from": "19",
"to": "21"
},
{
"from": "22",
"to": "24"
},
{
"from": "25"
}
]
}
}
}
}
'
(3)Date Range Aggregation
時間區間聚合專門針對date類型的字段,它與Range Aggregation的主要區別是其可以使用時間運算表達式。主要包括+(加法)運算、-(減法)運算和/(四捨五入)運算,每種運算都可以作用在不同的時間域上面,下面是一些時間運算表達式示例。
- now+10y:表示從現在開始的第10年。
- now+10M:表示從現在開始的第10個月。
- 1990-01-10||+20y:表示從1990-01-01開始後的第20年,即2010-01-01。
- now/y:表示在年位上做舍入運算。今天是2015-09-06,則這個表達式計算結果爲:2015-01-01。說好的rounding運算呢?結果是做的flooring運算,不知道爲啥,估計是我理解錯了-_-!!
下面查詢25年前及更早出生的學生數。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"range_age": {
"date_range": {
"field": "birthday",
"ranges": [
{
"to": "now-25y"
}
]
}
}
}
}
'
(4)Histogram Aggregation
直方圖聚合,它將某個number類型字段等分成n份,統計落在每一個區間內的記錄數。它與前面介紹的Range聚合非常像,只不過Range可以任意劃分區間,而Histogram做等間距劃分。既然是等間距劃分,那麼參數裏面必然有距離參數,就是interval參數。下面按學生年齡統計各個年齡段內的學生數量,分隔距離爲2歲。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"histogram_age": {
"histogram": {
"field": "age",
"interval": 2, // 距離爲2
"min_doc_count": 1 // 只返回記錄數量大於等於1的區間
}
}
}
}
'
(5)Date Histogram Aggregation
時間直方圖聚合,專門對時間類型的字段做直方圖聚合。這種需求是比較常用見得的,我們在統計時,通常就會按照固定的時間斷(1個月或1年等)來做統計。下面統計學校中同一年出生的學生數。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"data_histogram_birthday": {
"date_histogram": {
"field": "birthday",
"interval": "year", // 按年統計
"format": "yyyy" // 返回結果的key的格式
}
}
}
}
'
返回結果如下,可以看到由於上面的”format”: “yyyy”,所以返回的key_as_string只返回年的信息。
{
"buckets": [
{
"key_as_string": "1985",
"key": 473385600000,
"doc_count": 1
},
{
"key_as_string": "1986",
"key": 504921600000,
"doc_count": 1
},
{
"key_as_string": "1987",
"key": 536457600000,
"doc_count": 1
},
{
"key_as_string": "1989",
"key": 599616000000,
"doc_count": 1
},
{
"key_as_string": "1990",
"key": 631152000000,
"doc_count": 1
},
{
"key_as_string": "1991",
"key": 662688000000,
"doc_count": 1
},
{
"key_as_string": "1992",
"key": 694224000000,
"doc_count": 1
},
{
"key_as_string": "1994",
"key": 757382400000,
"doc_count": 1
}
]
}
(6)Missing Aggregation
值缺損聚合,它是一類單桶聚合,也就是最終只會產生一個“桶”。下面統計學生信息中地址欄缺損的記錄數量。由於只有學號爲6的孫尚香的地址缺損,所以統計值爲1。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"missing_address": {
"missing": {
"field": "address"
}
}
}
}
'
1.3 嵌套使用
前面已經說過,聚合操作是可以嵌套使用的。通過嵌套,可以使得metric類型的聚合操作作用在每一“桶”上。我們可以使用ES的嵌套聚合操作來完成稍微複雜一點的統計功能。下面統計每一個班裏最大的年齡值。
curl -XPOST "192.168.1.101:9200/student/student/_search?search_type=count" -d
'
{
"aggs": {
"missing_address": {
"terms": {
"field": "classNo"
},
"aggs": { // 在這裏嵌套新的子聚合
"max_age": {
"max": { // 使用max聚合
"field": "age"
}
}
}
}
}
}
'
返回結果如下:
{
"buckets": [
{
"key": "1", // key是班級號
"doc_count": 3, // 每個班級內的人數
"max_age": { // 這裏是我們指定的子聚合名
"value": 24, // 每班的年齡值
"value_as_string": "24.0"
}
},
{
"key": "2",
"doc_count": 3,
"max_age": {
"value": 23,
"value_as_string": "23.0"
}
},
{
"key": "3",
"doc_count": 1,
"max_age": {
"value": 20,
"value_as_string": "20.0"
}
},
{
"key": "4",
"doc_count": 1,
"max_age": {
"value": 16,
"value_as_string": "16.0"
}
}
]
}
2. 總結
本文介紹了ES中的一些常用的聚合API的使用,包括metric、bucketing以及它們的嵌套使用方法。掌握了這些API就可以完成簡單的數據統計功能,更多的API詳見官方文檔。
想進階的同學,請看:ES權威指南