Elasticsearch 除了在搜索方面非常之快,对数据分析也是非常重要的一面。正确理解 Bucket Aggregation 对我们使用 Kibana 非常重要。Elasticsearch 提供了非常多的 Aggregation 可以供我们使用。其中 Bucket aggregation 对于初学者来说也是比较不容易理解的一个。在今天的这篇文章中,我来重点讲述这个。
原文地址:https://blog.csdn.net/UbuntuTouch/article/details/103679273
透彻理解 Elasticsearch 中的 Bucket Aggregation
简单地说:一个桶代表一个具有共同标准的文档集合。存储桶(bucket)是聚合的关键要素。比如,我们想分析每个月的 log 流量:
存储桶聚合(bucket Aggregation)不像指标聚合(Metric Aggregation)那样计算字段的指标,而是创建文档存储桶。每个存储桶都与一个标准(取决于聚合类型)相关联,该标准确定当前上下文中的文档是否“落入”其中。换句话说,存储桶有效地定义了文档集。除了存储桶本身之外,存储桶聚合还计算并返回落入每个存储桶的文档数量。
与指标聚合相反,存储桶聚合可以保存子聚合。这些子聚合将针对其“父”存储桶聚合创建的存储桶进行聚合。
有不同的存储桶聚合器,每个聚合器都有不同的“存储桶”策略。一些定义单个存储桶,一些定义固定数量的多个存储桶,另一些定义在聚合过程中动态创建存储桶。
尽管存储桶聚合不计算指标,但它们可以包含可以为存储桶聚合生成的每个存储桶计算指标的指标子聚合。这使存储桶聚合对于粒度表示和分析 Elasticsearch 索引非常有用。在本文中,我们将重点介绍直方图(histogram),范围(range),过滤器(filter)和术语(terms)等存储桶聚合。让我们开始吧!
什么是桶?
首先为了说明问题的方便,我们来展示一个简单的 SpreadSheet 表格:
在上面的表格中,我们可以看到一个很规整的关于用户的名单。每天用户具有 id,user,age,country 及 category。当这些数据被存于到 Elasticsearch 中后,会变成一个一个的文档:
假如我们想得到这些个用户的平均年龄,我们很容易通过 Elasticsearch 的 Avg Aggregation 来得到。
那么他们的平均年龄是34岁。
接下来我们开始谈我们的重点了:Bucket Aggregation。
简单地说:Bucket Aggregation 是一种把具有相同标准的数据分组数据的方法。创建存储桶:
收集具有共同标准的文件
‒可以具有一个或多个与其关联的指标
bucket 每个存储桶的文档数(文档数)是默认指标
首先,我们可以按照 cetegory 进行分类:
我们从上面的表格可以看出来 category A 有 3 个文档,而 category B 有 3 个文档。
上面我们得到了每个 category 的数量是我们想要的,但是在很多的情况下,我们更想得到在这每天 category 下的一些指标,比如每个 category 的平均年龄是多少?这样我实际上是在以 category 为 key 的存储桶里来求平均值。
我们可以通过如下的方法来得到这个:
这样,我们就得到了在每个 category 下的平均年龄。我们可以再进一步想得到在每个 category 下的每个国家的平均年龄。显然这个时候,我们需要使用到 country这个桶,这桶是在 category 桶下面的另外一个桶。
如果大家对上面的实验有兴趣,可以把如下的数据导入到 Elasticsearch 中:
PUT users { "mappings": { "properties": { "age": { "type": "long" }, "category": { "type": "keyword" }, "country": { "type": "keyword" }, "user": { "type": "keyword" } } } }
我们使用 Bulk API 来导入数据:
POST _bulk { "index" : { "_index" : "users", "_id": 1} } {"user":"bill", "age": 30, "country": "FR", "category": "A"} { "index" : { "_index" : "users", "_id": 2} } {"user":"Marie", "age": 32, "country": "US", "category": "A"} { "index" : { "_index" : "users", "_id": 3} } {"user":"Clarie", "age": 32, "country": "US", "category": "A"} { "index" : { "_index" : "users", "_id": 4} } {"user":"Tom", "age": 44, "country": "DE", "category": "B"} { "index" : { "_index" : "users", "_id": 5} } {"user":"John", "age": 40, "country": "US", "category": "B"} { "index" : { "_index" : "users", "_id": 6} } {"user":"Emma", "age": 26, "country": "US", "category": "B"}
最后一步的查询:
GET users/_search { "size": 0, "aggs": { "categories": { "terms": { "field": "category" }, "aggs": { "countries": { "terms": { "field": "country" }, "aggs": { "average_age": { "avg": { "field": "age" } } } } } } } }
显示结果:
1 { 2 "took" : 2, 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" : 6, 13 "relation" : "eq" 14 }, 15 "max_score" : null, 16 "hits" : [ ] 17 }, 18 "aggregations" : { 19 "categories" : { 20 "doc_count_error_upper_bound" : 0, 21 "sum_other_doc_count" : 0, 22 "buckets" : [ 23 { 24 "key" : "A", 25 "doc_count" : 3, 26 "countries" : { 27 "doc_count_error_upper_bound" : 0, 28 "sum_other_doc_count" : 0, 29 "buckets" : [ 30 { 31 "key" : "US", 32 "doc_count" : 2, 33 "average_age" : { 34 "value" : 32.0 35 } 36 }, 37 { 38 "key" : "FR", 39 "doc_count" : 1, 40 "average_age" : { 41 "value" : 30.0 42 } 43 } 44 ] 45 } 46 }, 47 { 48 "key" : "B", 49 "doc_count" : 3, 50 "countries" : { 51 "doc_count_error_upper_bound" : 0, 52 "sum_other_doc_count" : 0, 53 "buckets" : [ 54 { 55 "key" : "US", 56 "doc_count" : 2, 57 "average_age" : { 58 "value" : 33.0 59 } 60 }, 61 { 62 "key" : "DE", 63 "doc_count" : 1, 64 "average_age" : { 65 "value" : 44.0 66 } 67 } 68 ] 69 } 70 } 71 ] 72 } 73 } 74 }