es笔记六之聚合操作之指标聚合

打印 上一主题 下一主题

主题 872|帖子 872|积分 2626

本文首发于公众号:Hunter后端
原文链接:es笔记六之聚合操作之指标聚合
聚合操作,在 es 中的聚合可以分为大概四种聚合:

  • bucketing(桶聚合)
  • mertic(指标聚合)
  • matrix(矩阵聚合)
  • pipeline(管道聚合)
bucket
类似于分类分组,按照某个 key 将符合条件的数据都放到该类别的组中
mertic
计算一组文档的相关值,比如最大,最小值
matrix
根据多个 key 从文档中提取值生成矩阵,这个操作不支持脚本(script)
pipeline
将其他聚合的结果再次聚合输出
聚合是支持套娃(嵌套)操作的,你可以在聚合的结果上接着进行聚合操作,es 是不限制聚合的深度的。
本篇笔记目录如下:

  • 指标聚合的基本结构
  • 平均值聚合
  • 去重统计
  • 聚合统计汇总
  • 最大值、最小值聚合
  • 百分位统计
  • 百分位排名
  • 字符串统计聚合
  • sum 统计总和操作
  • count 统计总数操作
  • top hit 操作
1、指标聚合的基本结构

指标聚合操作的基本结构大致如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "aggregation_name": {
  6.       "agg_name": {
  7.         "field": "field_name"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
其中,aggregation_name 为聚合返回结果的名称,由我们自己定义,agg_name 为聚合的参数,比如最大值最小值,平均值等,这个我们在下面介绍。
指标聚合
指标聚合是从文档中提取字段值出来进行计算得出结果,比如最大最小平均值等。
接下来将详细介绍各种指标聚合操作。
2、平均值聚合
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "avg_balance": {
  6.       "avg": {
  7.         "field": "balance"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
其中,最外层的 aggs 表示是聚合操作,avg_balance 是聚合的名称,avg 则表示是平均值聚合,里面的 field 表示聚合的字段是 balance 字段
在这里,如果不添加 size=0,除了会返回我们的聚合结果,还会返回聚合的源数据。
这个操作我们返回的结果如下:
  1. {
  2.   "took" : 1,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 1,
  6.     "successful" : 1,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 1000,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "aggregations" : {
  19.     "avg_balance" : {
  20.       "value" : 25714.837
  21.     }
  22.   }
  23. }
复制代码
我们聚合的结果在 aggregations 这个 key 下。
脚本执行
脚本执行的方式如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "avg_balance": {
  6.       "avg": {
  7.         "script": {"source": "doc.balance.value"}
  8.       }
  9.     }
  10.   }
  11. }
复制代码
对结果处理
假设,我们需要对这个平均值结果进行处理,比如我们计算出来的这个值是 2000,我们想要对这个值进行修正,比如乘以 1.2。
当然,这个乘的操作我们可以获取数据之后在系统里进行操作,如果是直接在 es 的处理中,我们可以如下实现:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "avg_corrected_balance": {
  6.       "avg": {
  7.         "field": "balance",
  8.         "script": {
  9.           "lang": "painless",
  10.           "source": "_value * params.correction",
  11.           "params": {"correction": 1.2}
  12.          
  13.         }
  14.       }
  15.     },
  16.     "avg_balance": {
  17.       "avg": {
  18.         "script": {"source": "doc.balance.value"}
  19.       }
  20.     }
  21.   }
  22. }
复制代码
在上面的语句中,我们新增了一个 params 字段,定义了一个 correction 的值,然后返回的结果乘以了这个值。
在这里,我额外加了一个 avg_balance,是直接用的平均值聚合结果,主要是用来对比这两个结果。
缺失值补充
有一些情况,我们在导入数据的时候,可能某条数据的某个字段是没有值的,默认情况下他们是会被忽略的,不计入计算的,但是如果想要为其加一个默认值也是可以实现的,这里我们用到 missing 这个参数来定义:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "avg_balance": {
  6.       "avg": {
  7.         "field": "balance",
  8.         "missing": 0
  9.       }
  10.     }
  11.   }
  12. }
复制代码
3、去重统计

是对某个字段进行去重后统计总数,操作如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_count": {
  6.       "cardinality": {
  7.         "field": "age"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
需要注意的是,这个统计对于 text 字段属性是不生效的
4、聚合统计汇总

有一个聚合统计汇总的参数 stats,可以将一般的聚合值进行汇总后返回,比如总数,最大值,最小值等,使用如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_stats": {
  6.       "stats": {
  7.         "field": "age"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
可以看到返回的值如下:
  1. {
  2. ...
  3. "aggregations" : {
  4.     "age_stats" : {
  5.       "count" : 1000,
  6.       "min" : 20.0,
  7.       "max" : 40.0,
  8.       "avg" : 30.171,
  9.       "sum" : 30171.0
  10.     }
  11.   }
  12. }
复制代码
如果还想获得方差,标准差等数据,可以使用这个参数的扩展版 extended_stats,替换聚合的参数 stats 即可。
5、最大值、最小值聚合

最大值最小值的关键字是 max 和 min,使用示例如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "max_age": {
  6.       "max": {"field": "age"}
  7.     },
  8.     "min_age": {
  9.       "min": {"field": "age"}
  10.     }
  11.   }
  12. }
复制代码
使用脚本的方式来实现:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "max_age": {
  6.       "max": {"script": {"source": "doc.age.value"}}
  7.     }
  8.   }
  9. }
复制代码
6、百分位统计

使用 es 进行百分位的统计,用到的关键字是 percentiles
使用示例如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_percentiles": {
  6.       "percentiles": {
  7.         "field": "age"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
会输出 [1, 5, 25, 75, 95, 99] 的统计数:
  1. {
  2.   ...
  3.   "aggregations" : {
  4.     "age_percentiles" : {
  5.       "values" : {
  6.         "1.0" : 20.0,
  7.         "5.0" : 21.0,
  8.         "25.0" : 25.0,
  9.         "50.0" : 30.8,
  10.         "75.0" : 35.0,
  11.         "95.0" : 39.0,
  12.         "99.0" : 40.0
  13.       }
  14.     }
  15.   }
  16. }
复制代码
我们也可以指定统计的百分位的数列表,比如我们只想知道 [75, 98, 99, 99.9] 的数据:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_percentiles": {
  6.       "percentiles": {
  7.         "field": "age",
  8.         "percents": [75, 98, 99, 99.9]
  9.       }
  10.     }
  11.   }
  12. }
复制代码
我们直接使用是返回的百分位-数据的格式,我们也可以使用 {'key': xx, 'value': xx} 来返回一个列表,加上一个参数 keyed=false 即可
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_percentiles": {
  6.       "percentiles": {
  7.         "field": "age",
  8.         "keyed": false
  9.       }
  10.     }
  11.   }
  12. }
复制代码
返回的结果示例如下:
  1.     "age_percentiles" : {
  2.       "values" : [
  3.          ...
  4.         {
  5.           "key" : 75.0,
  6.           "value" : 35.0
  7.         },
  8.         {
  9.           "key" : 95.0,
  10.           "value" : 39.0
  11.         },
  12.         {
  13.           "key" : 99.0,
  14.           "value" : 40.0
  15.         }
  16.       ]
  17.     }
  18.   }
  19. }
复制代码
7、百分位排名

这个是和前面的百分位统计相反的操作。
前面是根据百分位获取该百分位值,这个参数的作用是根据数据获取在系统中的百分位,使用示例如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_ranks": {
  6.       "percentile_ranks": {
  7.         "field": "age",
  8.         "values": [
  9.           30,
  10.           35,
  11.           40
  12.         ]
  13.       }
  14.     }
  15.   }
  16. }
复制代码
8、字符串统计聚合

对于字符串类型的数据,有一个专门的参数来获取相应的聚合统计值,为 string_stats
对 lastname 字段的统计示例如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "last_name_stats": {
  6.       "string_stats": {"field": "lastname.keyword"}
  7.     }
  8.   }
  9. }
复制代码
需要注意,如果我们需要进行统计的字段如果是 text 字段,那么就需要加上 .keyword 来进行统计,如果是字段属性是 keyword,就不需要这样处理。
经过统计返回的数据如下:
  1.   ...
  2.   "aggregations" : {
  3.     "last_name_stats" : {
  4.       "count" : 1000,
  5.       "min_length" : 2,
  6.       "max_length" : 11,
  7.       "avg_length" : 6.122,
  8.       "entropy" : 4.726472133462717
  9.     }
  10.   }
  11. }
复制代码
以上信息包括数据总数,lastname 字段最长和最短长度,平均长度和熵值
9、sum 统计总和操作

比如我们需要对 bank 这个数据库的 age 字段进行 sum 的操作,可以如下操作:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_sum": {
  6.       "sum": {"field": "age"}
  7.     }
  8.   }
  9. }
复制代码
在前面的每一个聚合操作里,都可以进行 query 的条件筛选,比如获取 age=21 的数据的 sum 值:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "query": {"match": {"age": "21"}},
  5.   "aggs": {
  6.     "age_sum": {
  7.       "sum": {"field": "age"}
  8.     }
  9.   }
  10. }
复制代码
10、count 统计总数操作

count 是统计总数,使用示例如下:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "age_count": {
  6.       "value_count": {
  7.         "field": "age"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
11、top hit 操作

top hit 操作是根据条件返回符合条件的前几条数据,通过 size 控制返回的数量。
我们先来看下下面的这个操作:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "top_ages": {
  6.       "terms": {
  7.         "field": "age",
  8.         "size": 30
  9.       }
  10.     }
  11.   }
  12. }
复制代码
这个操作其实就是一个桶聚合,它会在下一篇笔记中介绍,这里我们直接用一下,它返回字段为 age,以及它在文档中的数量:
  1.   ...
  2.   "aggregations" : {
  3.     "top_ages" : {
  4.       "doc_count_error_upper_bound" : 0,
  5.       "sum_other_doc_count" : 0,
  6.       "buckets" : [
  7.         {
  8.           "key" : 31,
  9.           "doc_count" : 61
  10.         },
  11.         {
  12.           "key" : 39,
  13.           "doc_count" : 60
  14.         },
  15.         {
  16.           "key" : 26,
  17.           "doc_count" : 59
  18.         },
  19.         ...
复制代码
top_hits 的操作是在第一个 aggs 聚合操作条件下,进行再次聚合。
比如我们想要获取各个 age 的数据中,按照 balance 字段进行倒序排序的前三个,我们可以如下操作:
  1. GET /bank/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "top_ages": {
  6.       "terms": {
  7.         "field": "age",
  8.         "size": 30
  9.       },
  10.       "aggs": {
  11.         "top_balance_hits": {
  12.           "top_hits": {
  13.             "size": 3,
  14.             "sort": [{"balance": {"order": "desc"}}]
  15.           }
  16.         }
  17.       }
  18.     }
  19.   }
  20. }
复制代码
然后在第一次聚合返回的结果中,就会多一个 top_balance_hits 字段,也就是我们在查询操作中指定的,其下会有三条按照 balance 字段倒序返回的数据:
  1.   ...
  2.   "aggregations" : {
  3.     "top_ages" : {
  4.       "doc_count_error_upper_bound" : 0,
  5.       "sum_other_doc_count" : 0,
  6.       "buckets" : [
  7.         {
  8.           "key" : 31,
  9.           "doc_count" : 61,
  10.           "top_balance_hits" : {
  11.             "hits" : {
  12.               "total" : {
  13.                 "value" : 61,
  14.                 "relation" : "eq"
  15.               },
  16.               "max_score" : null,
  17.               "hits" : [
  18.                 ...
  19.               ]
  20.         },
  21.         {
  22.           "key" : 39,
  23.           "doc_count" : 60,
  24.           ...
  25.         },
  26.         {
  27.           "key" : 26,
  28.           "doc_count" : 59,
  29.           ...
  30.         },
  31.         ...
复制代码
如果想获取更多后端相关文章,可扫码关注阅读:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表