目录

1. 简介

直方图聚合是一种基于多桶值聚合,可从文档中提取的数值数值范围值来进行聚合。它可以对参与聚合的值来动态的生成固定大小的桶。

2. bucket_key如何计算

假设我们有一个值是32,并且桶的大小是5,那么32四舍五入后变成30,因此文档将落入与键30关联的存储桶中。下面的算式可以精确的确定每个文档的归属桶

bucket_key = Math.floor((value - offset) / interval) * interval + offset

  1. offset:的值默认是从0开始。并且offset的值必须在[0, interval)之间。且需要是一个正数
  2. value:值的参与计算的值,比如某个文档中的价格字段等。

3. 有一组数据,如何确定是落入到那个桶中

此处是我自己的一个理解,如果错误欢迎指出。

存在的数据: [3, 8, 15]

offset = 0

interval = 5

那么可能会分成如下几个桶 [0,5) [5,10) [10, 15) [15,+∞)

  1. 数字3落入的桶 buket_key= Math.floor((3 - 0) / 5) * 5 + 0 = 0,即落入[0,5)这个桶中
  2. 数字8落入的桶 buket_key= Math.floor((8 - 0) / 5) * 5 + 0 = 5,即落入[5,10)这个桶中
  3. 数字15落入的桶 buket_key= Math.floor((15 - 0) / 5) * 5 + 0 = 15,即落入[15,+∞)这个桶中

4、需求

我们有一组api响应时间数据,根据这组数据进行histogram聚合统计

4.1 准备mapping

PUT /index_api_response_time
{
"settings": {
"number_of_shards": 1
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"api": {
"type": "keyword"
},
"response_time": {
"type": "integer"
}
}
}
}

此处的mapping比较简单,就3个字段idapiresponse_time

4.2 准备数据

PUT /index_api_response_time/_bulk
{"index":{"_id":1}}
{"api":"/user/infos","response_time": 3}
{"index":{"_id":2}}
{"api":"/user/add"}
{"index":{"_id":3}}
{"api":"/user/update","response_time": 8}
{"index":{"_id":4}}
{"api":"/user/list","response_time": 15}
{"index":{"_id":5}}
{"api":"/user/export","response_time": 30}
{"index":{"_id":6}}
{"api":"/user/detail","response_time": 32}

此处先记录 id=2的数据,这个是没有response_time的,后期聚合时额外处理。

5、histogram聚合操作

5.1、根据response_time聚合,间隔为5

5.1.1 dsl

GET /index_api_response_time/_search
{
"size": 0,
"aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5
}
}
}
}

5.1.2 java代码

@Test
@DisplayName("根据response_time聚合,间隔为5")
public void test01() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.aggregations("agg_01", agg -> agg.histogram(histogram -> histogram.field("response_time")
.interval(5D))));
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.1.3 运行结果

5.2 在5.1基础上聚合出每个桶总的响应时间

此处聚合一下是为了结合已有的数据,看看每个数据是否落入到了相应的桶中

5.2.1 dsl

GET /index_api_response_time/_search
{
"size": 0, "aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5
},
"aggs": {
"agg_sum": {
"sum": {
"field": "response_time"
}
}
}
}
}
}

5.2.2 java代码

@Test
@DisplayName("在test01基础上聚合出每个桶总的响应时间")
public void test02() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.aggregations("agg_01", agg ->
agg.histogram(histogram -> histogram.field("response_time").interval(5D))
.aggregations("agg_sum", aggSum -> aggSum.sum(sum -> sum.field("response_time")))
));
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.2.3 运行结果

5.3 每个桶中必须存在1个文档的结果才返回-min_doc_count

从5.1中的结果我们可以知道,不管桶中是否存在数据,我们都返回了,即返回了很多空桶。 简单理解就是返回的 桶中存在 doc_count=0 的数据,此处我们需要将这个数据不返回

5.3.1 dsl

GET /index_api_response_time/_search
{
"size": 0, "aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5,
"min_doc_count": 1
}
}
}
}

5.3.2 java代码

@Test
@DisplayName("每个桶中必须存在1个文档的结果才返回-min_doc_count")
public void test03() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.aggregations("agg_01", agg -> agg.histogram(
histogram -> histogram.field("response_time").interval(5D).minDocCount(1)
)
)
);
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.3.3 运行结果

5.4 补充空桶数据-extended_bounds

这个是什么意思?假设我们通过 response_time >= 10 进行过滤,并且 interval=5 那么es默认情况下就不会返回 bucket_key =0,5,10的桶,那么如果我想返回那么该如何处理呢?可以通过 extended_bounds 来实现

使用extended_bounds时,min_doc_count=0时才有意义。 extended_bounds不会过滤桶。

5.4.1 dsl

GET /index_api_response_time/_search
{
"size": 0,
"query": {
"range": {
"response_time": {
"gte": 10
}
}
},
"aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5,
"min_doc_count": 0,
"extended_bounds": {
"min": 0,
"max": 50
}
}
}
}
}

5.4.2 java代码

@Test
@DisplayName("补充空桶数据-extended_bounds")
public void test04() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
.aggregations("agg_01", agg -> agg.histogram(
histogram -> histogram.field("response_time").interval(5D).minDocCount(0)
.extendedBounds(bounds -> bounds.min(1D).max(50D))
)
)
);
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.4.3 运行结果

5.5 只展示min-max之间的桶-hard_bounds



此处的数据:

PUT /index_api_response_time/_bulk
{"index":{"_id":1}}
{"api":"/user/infos","response_time": 3}
{"index":{"_id":2}}
{"api":"/user/add"}
{"index":{"_id":3}}
{"api":"/user/update","response_time": 8}
{"index":{"_id":4}}
{"api":"/user/list","response_time": 15}
{"index":{"_id":5}}
{"api":"/user/export","response_time": 25}
{"index":{"_id":6}}
{"api":"/user/detail","response_time": 32}

5.5.1 dsl

GET /index_api_response_time/_search
{
"size": 0,
"query": {
"range": {
"response_time": {
"gte": 10
}
}
},
"aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5,
"min_doc_count": 0,
"hard_bounds": {
"min": 15,
"max": 25
}
},
"aggs": {
"a_s": {
"sum": {
"field": "response_time"
}
}
}
}
}
}

5.5.2 java代码

@Test
@DisplayName("只展示min-max之间的桶-hard_bounds")
public void test05() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
.aggregations("agg_01", agg ->
agg.histogram(
histogram -> histogram.field("response_time").interval(5D).minDocCount(0)
.hardBounds(bounds -> bounds.min(1D).max(50D))
)
.aggregations("a_s", sumAgg -> sumAgg.sum(sum -> sum.field("response_time")))
)
);
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.5.3 运行结果

5.6 排序-order

By default the returned buckets are sorted by their key ascending, though the order behaviour can be controlled using the order setting. Supports the same order functionality as the Terms Aggregation.

5.6.1 dsl

GET /index_api_response_time/_search
{
"size": 0,
"query": {
"range": {
"response_time": {
"gte": 10
}
}
},
"aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5,
"order": {
"_count": "desc"
}
}
}
}
}

5.6.2 java代码

@Test
@DisplayName("排序order")
public void test06() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
.aggregations("agg_01", agg ->
agg.histogram(
histogram -> histogram.field("response_time").interval(5D)
.order(NamedValue.of("_count", SortOrder.Desc))
)
)
);
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.6.3 运行结果

5.7 文档中缺失聚合字段时如何处理-missing

5.7.1 dsl

GET /index_api_response_time/_search
{
"size": 0,
"aggs": {
"agg_01": {
"histogram": {
"field": "response_time",
"interval": 5,
"missing": 0
}
}
}
}

5.7.2 java代码

@Test
@DisplayName("文档中缺失聚合字段时如何处理-missing")
public void test07() throws IOException {
SearchRequest request = SearchRequest.of(search ->
search
.index("index_api_response_time")
.size(0)
.query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
.aggregations("agg_01", agg ->
agg.histogram(
histogram -> histogram.field("response_time").interval(5D) .missing(0D)
)
)
);
System.out.println("request: " + request);
SearchResponse<String> response = client.search(request, String.class);
System.out.println("response: " + response);
}

5.7.3 运行结果

6、完整代码

https://gitee.com/huan1993/spring-cloud-parent/blob/master/es/es8-api/src/main/java/com/huan/es8/aggregations/bucket/HistogramAggs.java

7、参考文档

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html

elasticsearch 之 histogram 直方图聚合的更多相关文章

  1. Elasticsearch聚合 之 Histogram 直方图聚合

    Elasticsearch支持最直方图聚合,它在数字字段自动创建桶,并会扫描全部文档,把文档放入相应的桶中.这个数字字段既可以是文档中的某个字段,也可以通过脚本创建得出的. 桶的筛选规则 举个例子,有 ...

  2. ElasticSearch 2 (37) - 信息聚合系列之内存与延时

    ElasticSearch 2 (37) - 信息聚合系列之内存与延时 摘要 控制内存使用与延时 版本 elasticsearch版本: elasticsearch-2.x 内容 Fielddata ...

  3. ElasticSearch 2 (34) - 信息聚合系列之多值排序

    ElasticSearch 2 (34) - 信息聚合系列之多值排序 摘要 多值桶(terms.histogram 和 date_histogram)动态生成很多桶,Elasticsearch 是如何 ...

  4. ElasticSearch 2 (31) - 信息聚合系列之时间处理

    ElasticSearch 2 (31) - 信息聚合系列之时间处理 摘要 如果说搜索是 Elasticsearch 里最受欢迎的功能,那么按时间创建直方图一定排在第二位.为什么需要使用时间直方图? ...

  5. ElasticSearch 2 (30) - 信息聚合系列之条形图

    ElasticSearch 2 (30) - 信息聚合系列之条形图 摘要 版本 elasticsearch版本: elasticsearch-2.x 内容 聚合还有一个令人激动的特性就是能够十分容易地 ...

  6. ElasticSearch 2 (38) - 信息聚合系列之结束与思考

    ElasticSearch 2 (38) - 信息聚合系列之结束与思考 摘要 版本 elasticsearch版本: elasticsearch-2.x 内容 本小节涵盖了许多基本理论以及很多深入的技 ...

  7. ElasticSearch 2 (36) - 信息聚合系列之显著项

    ElasticSearch 2 (36) - 信息聚合系列之显著项 摘要 significant_terms(SigTerms)聚合与其他聚合都不相同.目前为止我们看到的所有聚合在本质上都是简单的数学 ...

  8. ElasticSearch 2 (35) - 信息聚合系列之近似聚合

    ElasticSearch 2 (35) - 信息聚合系列之近似聚合 摘要 如果所有的数据都在一台机器上,那么生活会容易许多,CS201 课商教的经典算法就足够应付这些问题.但如果所有的数据都在一台机 ...

  9. ElasticSearch 2 (33) - 信息聚合系列之聚合过滤

    ElasticSearch 2 (33) - 信息聚合系列之聚合过滤 摘要 聚合范围限定还有一个自然的扩展就是过滤.因为聚合是在查询结果范围内操作的,任何可以适用于查询的过滤器也可以应用在聚合上. 版 ...

  10. ElasticSearch 2 (32) - 信息聚合系列之范围限定

    ElasticSearch 2 (32) - 信息聚合系列之范围限定 摘要 到目前为止我们看到的所有聚合的例子都省略了搜索请求,完整的请求就是聚合本身. 聚合与搜索请求同时执行,但是我们需要理解一个新 ...

随机推荐

  1. 一个包搞定中文数据集: datasetstore

    工作中,总是要使用各种中文数据集,每次使用数据集都要花费不少的时间进行寻找,写预处理代码,结合不同的模型和框架做出相应的处理.有的时候好不容易找到合适的数据集,但是却因为网络问题,无法下载,下载了很长 ...

  2. 使用『jQuery』『原生js』制作一个选项卡盒子 —— { }

    效果 HTML 部分 <body> <div id="main-box"> <div id="left-nav"></ ...

  3. 原生JavaScript对【DOM元素】的操作——增、删、改、查

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Spring配置XML本地提示

    Spring配置XML本地提示:点击eclipse属性-->选择XML Catalog 这里有一点要注意:要选择schema location

  5. 彻底掌握Makefile(一)

    彻底掌握Makefile(一) 介绍 makefile就是一个可以被make命令解析的文件,他定义了一系列编译的规则,帮助我们更加方便.简洁的去完成编译的过程.在一个大工程当中我们会有各种各样的文件, ...

  6. 我眼中的大数据(二)——HDFS

    Hadoop的第一个产品是HDFS,可以说分布式文件存储是分布式计算的基础,也可见分布式文件存储的重要性.如果我们将大数据计算比作烹饪,那么数据就是食材,而Hadoop分布式文件系统HDFS就是烧菜的 ...

  7. kubeoperator 使用外部mysql

    1.导出 kubeoperator 的数据库 sql 文件,然后导入到外部mysql 2.正常关闭 kubeoperator 3.关闭 kubeoperator 不会影响已经部署的 k8s 集群 4. ...

  8. logstash 读取MySQL数据到elasticsearch 相差8小时解决办法

    logstash和elasticsearch是按照UTC时间的,kibana却是按照正常你所在的时区显示的,是因为kibana中可以配置时区信息. 具体看这个: logstash 的配置文件添加 fi ...

  9. 【前端必会】不知道webpack插件? webpack插件源码分析BannerPlugin

    背景 不知道webpack插件是怎么回事,除了官方的文档外,还有一个很直观的方式,就是看源码. 看源码是一个挖宝的行动,也是一次冒险,我们可以找一些代码量不是很大的源码 比如webpack插件,我们就 ...

  10. 『现学现忘』Git后悔药 — 33、revert撤销(二)

    目录 4.一次移除某几次提交 (1)git revert移除某几次提交的修改 (2)git revert 移除某几次连续的提交的修改 5.revert命令常用参数 6.git revert和git r ...