ElasticSearch 2 (29) - 信息聚合系列之测试驱动
ElasticSearch 2 (29) - 信息聚合系列之测试驱动
摘要
我们可以用以下几页定义不同的聚合和它们的语法,但学习聚合的最佳途径就是用实例来说明。一旦我们获得了聚合的思想,以及如何合理地嵌套使用它们,那么语法就变得不那么重要。
版本
elasticsearch版本: elasticsearch-2.x
内容
我们可以用以下几页定义不同的聚合和它们的语法,但学习聚合的最佳途径就是用实例来说明。一旦我们获得了聚合的思想,以及如何合理地嵌套使用它们,那么语法就变得不那么重要。
注意
聚合的桶操作和度量的完整用法可以在 Elasticsearch 参考 中找到。本章中会涵盖其中很多内容,但在阅读完本章后查看它会有助于我们对它的整体能力有所了解。
所以让我们先看一个例子。我们将会创建一些对汽车经销商有用的聚合,数据是关于汽车交易的信息:车型、制造商、售价、何时被出售等。
首先我们新建并索引一些数据:
POST /cars/transactions/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }
有了数据,开始构建我们的第一个聚合。汽车经销商可能会想知道哪个颜色的汽车销量最好,用聚合可以轻易得到结果,用 terms 桶操作:
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : { #1
"popular_colors" : { #2
"terms" : { #3
"field" : "color"
}
}
}
}
#1 聚合操作被至于顶层参数 aggs 之下(如果愿意也可以用完整形式 aggregations 同样有效)。
#2 然后,可以为聚合指定一个我们想要名称,本例中是:popular_colors。
#3 最后,定义单个桶的类型 terms。
聚合是在特定搜索结果背景下执行的,这也就是说它只是另外一个查询请求的顶层参数(例如,使用 /_search 端点)。聚合可以与查询结对,但我们会晚些在 限定聚合的范围(Scoping Aggregations) 中来解决这个问题。
注意
可能会注意到我们将 size 设置成 0 。我们并不关心搜索结果的具体内容,所以将返回记录数设置为 0 来提高查询速度。设置
size: 0与 Elasticsearch 1.x 中使用count类型等价。
然后我们为聚合定义一个名字,名字的选择取决于使用者,响应的结果会以我们定义的名字为标签,这样应用就可以解析得到的结果。
随后我们定义聚合本身,在本例中,我们定义了一个单 terms 桶,它会为每个碰到的唯一词项动态创建新的桶。因为我们告诉它使用 color 字段,所以它会为每个颜色动态创建新桶。
让我们运行聚合并查看结果:
{
...
"hits": {
"hits": [] #1
},
"aggregations": {
"colors": { #2
"buckets": [
{
"key": "red", #3
"doc_count": 4 #4
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}
#1 因为我们设置了 size 参数,所以不会有 hits 搜索结果返回。
#2 colors 聚合是作为 aggregations 字段的一部分被返回的。
#3 每个桶的键值都与 color 字段里找到的唯一词对应。它总会包含doc_count 字段,告诉我们包含该词项的文档数量。
#4 每个桶的数量代表该颜色的文档数量。
响应包含多个桶,每个对应一个唯一颜色(例如:红 或 绿)。每个桶也包括“掉入”该桶的所有文档的数量。例如,有四两红色的车。
前面的这个例子完全是实时执行的:一旦文档可以被搜到,它就能被聚合。这也就意味着我们可以直接将聚合的结果源源不断的传入图形库,然后生成实时的仪表盘。只要销售了一辆银色的车,我们的图形就会立即动态更新银色车的统计信息。
瞧!这就是我们的第一个聚合!
混合度量(Adding a Metric to the Mix)
前面的例子告诉我们每个桶里面的文档数量,这很有用。但通常,我们的应用需要提供更复杂的文档度量。例如,每种颜色汽车的平均价格是多少?
为了获取更多信息,我们需要告诉 Elasticsearch 使用哪个字段,计算何种度量。这需要将度量嵌套在桶内,度量会基于桶内的文档计算统计结果。
让我们继续为汽车的例子加入 average 平均度量:
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": { #1
"avg_price": { #2
"avg": {
"field": "price" #3
}
}
}
}
}
}
#1 为度量新增 aggs 层。
#2 为度量指定名字:avg_price。
#3 最后,为 price 字段定义 avg 度量。
正如所见,我们用前面的例子加入了新的 aggs 层。这个新的聚合层让我们可以将 avg 度量嵌套置于桶内。实际上,这就为每个颜色生成了平均价格。
正如颜色的例子,我们需要给度量起一个名字(avg_price),这样可以稍后根据名字获取它的值。最后,我们指定度量本身(avg)以及我们想要计算平均值的字段(price):
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"avg_price": { #1
"value": 32500
}
},
{
"key": "blue",
"doc_count": 2,
"avg_price": {
"value": 20000
}
},
{
"key": "green",
"doc_count": 2,
"avg_price": {
"value": 21000
}
}
]
}
}
...
}
#1 响应中的新元素 avg_price
尽管响应只发生很小改变,实际上我们获得的数据是增长了。之前,我们知道有四两红色的车,现在,红色车的平均价格是 $32,500 美元。这个信息可以直接显示在报表或者图形中。
桶中之桶(Buckets Inside Buckets)
在我们使用不同的嵌套方案时,聚合的力量才能真正得以显现。在前例中,我们以及看到如何将一个度量嵌入桶中,它的功能以及十分强大了。
但真正令人激动的分析来自于将桶嵌套进另外一个桶所能得到的结果。现在,我们想要找出每个汽车制造商生产出来汽车颜色的分布:
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": { #1
"avg": {
"field": "price"
}
},
"make": { #2
"terms": {
"field": "make" #3
}
}
}
}
}
}
#1 注意前例中的 avg_price 度量仍然保持原位。
#2 另一个聚合 make 被加入到了 color 颜色桶中。
#3 这个聚合是 terms 桶,它会为每个汽车生成唯一的桶。
这里发生了一些有趣的事,首先,我们可能会观察到之前例子中的 avg_price 度量完全没有变化,还在原来的位置。不同层级的聚合都可以有多个度量或桶,avg_price 度量告诉我们每种颜色汽车的平均价格。它与其他的桶和度量相互独立。
这对我们的应用非常重要,因为这里面有很多相互关联,但又完全不同的度量需要收集。聚合使我们能够用一次数据请求获得所有的这些信息。
另外一件值得注意的重要事情是我们新增的这个 make 聚合,它是一个 terms 桶(嵌套在 colors terms 颜色桶内),这意味着它会为数据集中的每个唯一组合生成 (color, make) 元组。
让我们看看返回的响应(为了简单我们只显示部分结果)
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"make": { #1
"buckets": [
{
"key": "honda", #2
"doc_count": 3
},
{
"key": "bmw",
"doc_count": 1
}
]
},
"avg_price": {
"value": 32500 #3
}
},
...
}
#1 正如期望的那样,新的聚合嵌入在每个颜色桶中。
#2 现在我们看见按不同制造商分解的每种颜色下车辆信息。
#3 最终,我们看到前例中的 avg_price 度量仍然维持不变。
响应结果告诉我们以下几点:
- 红色车有四辆。
- 红色车的平均售价是 $32,500 美元。
- 其中三辆是 Honda 本田制造,一辆是 BMW 宝马制造。
最后的修改(One Final Modification)
让我们回到话题的原点,在进入新话题之前,对我们的示例做最后一个修改,为每个汽车生成商计算最低和最高的价格:
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": { "avg": { "field": "price" }
},
"make" : {
"terms" : {
"field" : "make"
},
"aggs" : { #1
"min_price" : { "min": { "field": "price"} }, #2
"max_price" : { "max": { "field": "price"} } #3
}
}
}
}
}
}
#1 我们需要增加另外一个嵌套的 aggs 层级。
#2 然后包括 min 最小度量。
#3 以及 max 最大度量。
得到以下输出(只显示部分结果):
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"make": {
"buckets": [
{
"key": "honda",
"doc_count": 3,
"min_price": {
"value": 10000 #1
},
"max_price": {
"value": 20000 #2
}
},
{
"key": "bmw",
"doc_count": 1,
"min_price": {
"value": 80000
},
"max_price": {
"value": 80000
}
}
]
},
"avg_price": {
"value": 32500
}
},
...
#1 #2 min 和 max 度量现在出现在每个汽车制造商下面。
有了这两个桶,我们可以对查询的结果进行扩展并得到以下信息:
- 有四辆红色车。
- 红色车的平均售价是 $32,500 美元。
- 其中三辆红色车是 Honda 本田制造,一辆是 BMW 宝马制造。
- 最便宜的红色本田售价为 $10,000 美元。
- 最贵的红色本田售价为 $20,000 美元。
参考
elastic.co:
Aggregation Test-Drive
ElasticSearch 2 (29) - 信息聚合系列之测试驱动的更多相关文章
- ElasticSearch 2 (37) - 信息聚合系列之内存与延时
ElasticSearch 2 (37) - 信息聚合系列之内存与延时 摘要 控制内存使用与延时 版本 elasticsearch版本: elasticsearch-2.x 内容 Fielddata ...
- ElasticSearch 2 (38) - 信息聚合系列之结束与思考
ElasticSearch 2 (38) - 信息聚合系列之结束与思考 摘要 版本 elasticsearch版本: elasticsearch-2.x 内容 本小节涵盖了许多基本理论以及很多深入的技 ...
- ElasticSearch 2 (36) - 信息聚合系列之显著项
ElasticSearch 2 (36) - 信息聚合系列之显著项 摘要 significant_terms(SigTerms)聚合与其他聚合都不相同.目前为止我们看到的所有聚合在本质上都是简单的数学 ...
- ElasticSearch 2 (35) - 信息聚合系列之近似聚合
ElasticSearch 2 (35) - 信息聚合系列之近似聚合 摘要 如果所有的数据都在一台机器上,那么生活会容易许多,CS201 课商教的经典算法就足够应付这些问题.但如果所有的数据都在一台机 ...
- ElasticSearch 2 (34) - 信息聚合系列之多值排序
ElasticSearch 2 (34) - 信息聚合系列之多值排序 摘要 多值桶(terms.histogram 和 date_histogram)动态生成很多桶,Elasticsearch 是如何 ...
- ElasticSearch 2 (33) - 信息聚合系列之聚合过滤
ElasticSearch 2 (33) - 信息聚合系列之聚合过滤 摘要 聚合范围限定还有一个自然的扩展就是过滤.因为聚合是在查询结果范围内操作的,任何可以适用于查询的过滤器也可以应用在聚合上. 版 ...
- ElasticSearch 2 (32) - 信息聚合系列之范围限定
ElasticSearch 2 (32) - 信息聚合系列之范围限定 摘要 到目前为止我们看到的所有聚合的例子都省略了搜索请求,完整的请求就是聚合本身. 聚合与搜索请求同时执行,但是我们需要理解一个新 ...
- ElasticSearch 2 (31) - 信息聚合系列之时间处理
ElasticSearch 2 (31) - 信息聚合系列之时间处理 摘要 如果说搜索是 Elasticsearch 里最受欢迎的功能,那么按时间创建直方图一定排在第二位.为什么需要使用时间直方图? ...
- ElasticSearch 2 (30) - 信息聚合系列之条形图
ElasticSearch 2 (30) - 信息聚合系列之条形图 摘要 版本 elasticsearch版本: elasticsearch-2.x 内容 聚合还有一个令人激动的特性就是能够十分容易地 ...
随机推荐
- Win8下IIS的安装和站点的公布
版权声明:本文为博主原创文章,不经博主同意注明链接就可以转载. https://blog.csdn.net/Senior_lee/article/details/32939411 之前 ...
- Thinkphp5.0分页和跳页
后台查询商品或者会员量需要用到分页展示列表,当页数比较多的时候为了体高用户体验度,需要添加一个跳页也就是手动输入页码数进行快速跳转指定页面.由于手动编写分页比较麻烦,又想使用TP5自带的分页,但是TP ...
- 抽象类、final关键字、多态
1.1 抽象类 1.1.1 抽象类概念 C extends B,B extends A,在继承过程中,形成一个继承金字塔,位于金字塔底部的类越来越具体(强大),位于塔顶的越来越抽象(简单). 例如:人 ...
- Kafka学习之路 (三)Kafka的高可用
一.高可用的由来 1.1 为何需要Replication 在Kafka在0.8以前的版本中,是没有Replication的,一旦某一个Broker宕机,则其上所有的Partition数据都不可被消费, ...
- String----是一个对象
* 字符串可以看成是字符组成的数组,但是js中没有字符类型 * 字符是一个一个的,在别的语言中字符用一对单引号括起来 * 在js中字符串可以使用单引号也可以使用双引号 * 因为字符串可以看成是数组,所 ...
- Node.js实战(十)之EventEmitter
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列. Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs. ...
- SpringMVC原理&MVC设计思想
什么是MVC? MVC是一种架构模式 --- 程序分层,分工合作,既相互独立,又协同工作 MVC是一种思考方式 --- 需要将什么信息展示给用户? 如何布局? 调用哪些业务逻辑? MVC流程图如下图所 ...
- std::max、std::min error C2589: “(”:“::”右边的非法标记,error C2059: 语法错误:“::”
在VC++种同时包含头文件#include <windows.h>和#include <algorithm>后就会出现无法正常使用std标准库中的min和max模板函数,经过查 ...
- Mac OS 上配置java开发环境
在开始本学期的java课程前,我需要先为自己的电脑配置好Java的开发环境.由于电脑是mac操作系统,所以教材上的教程对我并不管用,于是乎开始动手自己查阅网上资料来解决. 1.安装JDK 1.访问Or ...
- 写脚本时出现: Permission denied
例如对文件 remove.sh sudo chmod -R 777 remove.sh