Elasticsearch使用要点(六)-聚合

聚合 (group by)

在es中, 聚合可以跟搜索合并为一个请求, 它们使用相同的数据结构。这意味着聚合的执行速度很快并且就像搜索一样几乎是实时的。

注意: 聚合的结果不支持分页

概念

(Buckets): 满足特定条件的文档的集合. 类似于MySQL的GROUP BY.

指标(Metrics): 对桶内的文档进行统计计算. 类似MySQL的COUNT(), SUM(), MAX() 等聚合操作.

聚合 是由 指标 组成的。 聚合可能只有一个桶,可能只有一个指标,或者可能两个都有。也有可能有一些桶 嵌套(通过嵌套, 可以实现非常复杂的聚合统计) 在其他桶里面。

easy demo

请求:

1
2
3
4
5
6
7
8
9
10
11
GET /cars/transactions/_search
{
"size" : 0, // 指定size为0, 不关心搜索结果(hits为空), 提高查询速度.
"aggs" : { // 聚合参数.
"popular_colors" : { // 聚合名称.
"terms" : { // 单个桶的类型.
"field" : "color"
}
}
}
}

响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
...
"hits": {
"hits": [] // 前文设置了size, 故hits为空.
},
"aggregations": {
"popular_colors": { // 前文设置的聚合名称
"buckets": [ // 桶
{
"key": "red",
"doc_count": 4 // 默认指标
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}

关于指标: extended_stats指标可以返回很多统计字段.

more metrics

请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": { // 聚合名称
"terms": {
"field": "color" // 单个桶的类型
},
"aggs": { // 新增指标
"avg_price": { // 新增的指标名称.
"avg": { // 新增指标的含义
"field": "price"
}
}
}
}
}
}

响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
...
"aggregations": {
"colors": {
"buckets": [ // 桶
{
"key": "red",
"doc_count": 4,
"avg_price": { // 自定义的指标名称
"value": 32500 // 值
}
},
{
"key": "blue",
"doc_count": 2,
"avg_price": {
"value": 20000
}
},
{
"key": "green",
"doc_count": 2,
"avg_price": {
"value": 21000
}
}
]
}
}
...
}

nested buckets

请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
},
"make": { // 嵌套聚合. 含义为在上层聚合中, 增加单独的聚合.
"terms": {
"field": "make"
}
}
}
}
}
}

响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"make": { // 针对一个桶内的数据, 再次聚合运算.
"buckets": [
{
"key": "honda",
"doc_count": 3
},
{
"key": "bmw",
"doc_count": 1
}
]
},
"avg_price": {
"value": 32500
}
},

...
}

直方图

直方图使用histogram参数, 指定区间. 使用场景较窄, 可以参考官方文档

按时间统计

带有时间戳的文档, 可以使用参数date_histogram进行分析.

注意: 真特么坑爹的是, 周维度时间统计端点是周一早8点. 好像改不了.

统计每个月汽车销量:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "month",
"format": "yyyy-MM-dd"
}
}
}
}

响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
...
"aggregations": {
"sales": {
"buckets": [ // 空数据的月份不会显示出来
{
"key_as_string": "2014-01-01", // 时间
"key": 1388534400000,
"doc_count": 1
},
{
"key_as_string": "2014-02-01",
"key": 1391212800000,
"doc_count": 1
},
{
"key_as_string": "2014-05-01",
"key": 1398902400000,
"doc_count": 1
},
{
"key_as_string": "2014-07-01",
"key": 1404172800000,
"doc_count": 1
},
{
"key_as_string": "2014-08-01",
"key": 1406851200000,
"doc_count": 1
},
{
"key_as_string": "2014-10-01",
"key": 1412121600000,
"doc_count": 1
},
{
"key_as_string": "2014-11-01",
"key": 1414800000000,
"doc_count": 2
}
]
...
}

若需要显示范围内所有数据, 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "month",
"format": "yyyy-MM-dd",
"min_doc_count" : 0, // 强制返回空数据bucket
"extended_bounds" : { // 指定范围区间
"min" : "2014-01-01",
"max" : "2014-12-31"
}
}
}
}
}

限定聚合的数据范围

聚合操作可以加上参数query, 来与查询结合, 返回指定查询数据范围内的聚合.
如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /cars/transactions/_search
{
"query" : { // 范围
"match" : {
"make" : "ford"
}
},
"aggs" : { // 聚合
"colors" : {
"terms" : {
"field" : "color"
}
}
}
}

若在指定范围的聚合操作中, 还需要返回全局数据范围的聚合数据. 可以用global参数.
如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET /cars/transactions/_search
{
"size" : 0,
"query" : {
"match" : {
"make" : "ford"
}
},
"aggs" : {
"single_avg_price": {
"avg" : { "field" : "price" }
},
"all": { // 全局数据范围的聚合
"global" : {}, // 参数
"aggs" : {
"avg_price": {
"avg" : { "field" : "price" }
}

}
}
}
}

过滤buckets && 后过滤器

上文搭配query参数指定了数据范围进行聚合操作, 同时返回了相同范围内的查询与聚合. 若聚合操作的数据范围需要与查询操作的数据范围不同, 则可以使用 过滤buckets后过滤器 .

过滤buckets请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
GET /cars/transactions/_search
{
"size" : 0,
"query":{
"match": {
"make": "ford"
}
},
"aggs":{
"recent_sales": {
"filter": { // query返回的文档, 满足该filter时, 才放入bucket.(不影响查询结果)
"range": {
"sold": {
"from": "now-1M"
}
}
},
"aggs": {
"average_price":{
"avg": {
"field": "price"
}
}
}
}
}
}

后过滤器请求: (这个操作意为查询后操作, 会丢弃过滤操作的缓存, 可能性能差)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /cars/transactions/_search
{
"size" : 0,
"query": {
"match": {
"make": "ford"
}
},
"post_filter": { // 后过滤器, 在计算完全部查询后, 再对搜索结果进行过滤.(不影响聚合结果)
"term" : {
"color" : "green"
}
},
"aggs" : {
"all_colors": {
"terms" : { "field" : "color" }
}
}
}

小节:

  • 在 filter 过滤中的 non-scoring 查询. 同时影响搜索结果和聚合结果.
  • filter 桶影响聚合.
  • post_filter 只影响搜索结果.

聚合结果的排序

请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"terms" : {
"field" : "color",
"order": { // 排序
"_count" : "asc"
}
}
}
}
}

内置排序字段:

  • _count: 按文档数排序. 对 terms, histogram, date_histogram 有效.
  • _term: 按词项的字符串值的字母顺序排序. 只在terms内使用.
  • _key:按每个桶的键值数值排序(理论上与 _term 类似). 只在 histogramdate_histogram内使用.

按指标排序请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"terms" : {
"field" : "color",
"order": {
"avg_price" : "asc" // 指标升序
}
},
"aggs": {
"avg_price": { // 内置指标
"avg": {"field": "price"}
}
}
}
}
}

嵌套聚合的排序可以使用>符号将指标嵌套起来.