关于后端:elasticsearch-聚合之-datehistogram-聚合

39次阅读

共计 4140 个字符,预计需要花费 11 分钟才能阅读完成。

1、背景

此处来简略学习一下 elasticsearchdate_histogram直方图聚合。它和一般的直方图 histogram 聚合差不多,然而 date_histogram 只可于 日期或日期范畴 类型的值一起应用。

2、bucket_key 如何计算

  1. 假如咱们存在如下工夫 2022-11-29 23:59:59
  2. es中工夫为 2022-11-29 23:59:59 +0000,因为上方的工夫没有时区,所以会主动加上 0 时区,对应的工夫戳为 1669766399000
  3. 此处假如以 1d 为单位来聚合
  4. 聚合统计中 time_zone的值为+0800
  5. bucket_key 计算公式为 bucket_key = localToUtc(Math.floor(utcToLocal(value) / interval) * interval))

计算步骤如下:(此处是我本人的了解,如果不对欢送指出)

  • utcToLocal(value) = 1669766399000(utc 的值) + 8*60*60*1000(time_zone + 8 的值) = 1669795199000
  • Math.floor(utcToLocal(value) / interval) * interval) = Math.floor(1669795199000 / (24*60*60*1000)) * (24*60*60*1000) = 1669766400000
  • localToUtc(...)=1669766400000-86060*1000=1669737600000
  • key_as_string=utc 工夫 1669737600000 转换成东八区工夫展现为 =2022/11/30 00:00:00

3、前置常识

  1. 日期 (date) 类型的字段在 es中是以 long类型的值保留的。
  2. es中默认 默认的时区是 0 时区
  3. 如果咱们有一个东八区的工夫,那么在 es 中是如何存储的呢?
  • 假如存在如下 mapping

    "invoked_time": {
    "type": "date",
    "format": ["yyyy-MM-dd HH:mm:ss"]
    }
  • 如果咱们此时存在 如下 东八区 工夫 2022-11-29 12:12:12,那么在 es 会存储为 2022-11-29 12:12:12 +0000 对应的工夫戳,为什么会加上+0000,因为咱们本人的工夫字符串中没有时区,就会加上默认的 0 时区。

4、日历和固定工夫距离

既然咱们是依据工夫来进行聚合,那么必然就会波及到这么一个问题。假如以天为单位来聚合,那么 1 天 到底是 固定 24 小时 呢,还是 可变 的呢? 因为存在 时区 的关系,在有的国家,在某些时区下,一天就不肯定是 24 个小时。因而在 es 中提供了calendar-aware time intervals, 和 fixed time intervals. 两种类型。

4.1 Calendar intervals 日历距离

日历感知距离应用 calendar_interval 参数配置。 它能够主动感应到日历中的时区变动。它的单位只能是复数,不可是复数,比方 2d 就是谬误的。

日历距离 可用的单位为:分钟 (1m)、小时 (1h)、天 (1d)、星期 (1w)、月 (1M)、季度 (1q)、年 (1y)

举个例子:1m 是从何时开始的,何时完结的?.
所有的分钟都从 00 秒开始。一分钟是指定时区中第一分钟的 00 秒和下一分钟的 00 秒之间的工夫距离,用于弥补任何介于其间的闰秒,因而整点后的分钟数和秒数在开始和完结时是雷同的。

4.2 Fixed intervals 固定距离

固定距离应用 fixed_interval 参数进行配置。

与日历感知距离相比,固定距离是固定数量的 SI 单位,无论它们落在日历的哪个地位,都不会偏离。一秒总是由 1000ms 组成。这容许以反对的单位的任意倍数指定固定距离。然而,这意味着固定距离不能示意其余单位,例如月,因为一个月的持续时间不是固定的数量。尝试指定月或季度等日历距离将引发异样。

固定距离 可用的单位为:
毫秒 (ms)
秒 (s)
          定义为每个 1000 毫秒
分钟 (m)
          所有分钟都从 00 秒开始。定义为每个 60 秒 (60,000 毫秒)
小时 (h)
          所有小时都从 00 分 00 秒开始。定义为每 60 分钟 (3,600,000 毫秒)
天 (d)
          所有天都在尽可能早的工夫开始,通常是 00:00:00(午夜)。定义为 24 小时(86,400,000 毫秒)

5、数据筹备

5.1 筹备 mapping

PUT /index_api_invoked_time
{
  "settings": {"number_of_shards": 1},
  "mappings": {
    "properties": {
      "id": {"type": "long"},
      "api": {"type": "keyword"},
      "invoked_time": {
        "type": "date",
        "format": ["yyyy-MM-dd HH:mm:ss"]
      }
    }
  }
}

5.2 筹备数据

PUT /index_api_invoked_time/_bulk
{"index":{"_id":1}}
{"api":"/user/infos","invoked_time": "2022-11-26 00:00:00"}
{"index":{"_id":2}}
{"api":"/user/add"}
{"index":{"_id":3}}
{"api":"/user/update","invoked_time": "2022-11-26 23:59:59"}
{"index":{"_id":4}}
{"api":"/user/list","invoked_time": "2022-11-27 00:00:00"}
{"index":{"_id":5}}
{"api":"/user/export","invoked_time": "2022-11-29 23:59:59"}
{"index":{"_id":6}}
{"api":"/user/detail","invoked_time": "2022-12-01 01:00:00"}

6、聚合案例

6.1 dsl

POST /index_api_invoked_time/_search 
{
  "size": 0, 
  "aggregations": {
    "agg_01": {
      "date_histogram": {
        "field": "invoked_time",
        "calendar_interval": "1d",
        "min_doc_count": 0,
        "missing": "2022-11-27 23:59:59",
        "time_zone": "+08:00",
        "offset":"+10h",
        "extended_bounds": {
          "min": "2022-11-26 10:00:00",
          "max": "2022-12-03 10:00:00"
        }
      }
    }
  }
}

6.2 java 代码

@Test
@DisplayName("日期直方图聚合")
public void test01() throws IOException {
    SearchRequest request = SearchRequest.of(searchRequest ->
            searchRequest.index("index_api_invoked_time")
                    .size(0)
                    .aggregations("agg_01", agg ->
                            agg.dateHistogram(dateAgg ->
                                    // 聚合的字段
                                    dateAgg.field("invoked_time")
                                            // 聚合的单位,日历感知 单位为天,此时的一天不肯定为 24 小时,因为夏令时时,有些国家一天可能只有 23 个小时
                                            .calendarInterval(CalendarInterval.Day)
                                            // 固定距离,此处能够指定 1 天就是 24 小时
                                            // .fixedInterval()
                                            // 如果聚合的桶中,没有文档也返回
                                            .minDocCount(0)
                                            // 对于文档中,聚合字段缺失,此处给一个默认值,默认状况是此文档不参加聚合
                                            .missing(DateTime.of("2022-11-27 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                                            // 时区
                                            .timeZone("+08:00")
                                            // 偏移,偏移是在工夫在对应的时区调整之后,再去偏移
                                            .offset(time -> time.time("+10h"))
                                            // 如果返回的桶数据不在这个边界中,则给默认值,不会对数据进行过滤。.extendedBounds(bounds ->
                                                    bounds.min(FieldDateMath.of(f -> f.expr("2022-11-26 10:00:00")))
                                                            .max(FieldDateMath.of(f -> f.expr("2022-12-03 10:00:00")))
                                            )
                            )
                    )
    );
    System.out.println("request:" + request);
    SearchResponse<String> response = client.search(request, String.class);
    System.out.println("response:" + response);
}

6.3 聚合后果

7、残缺代码

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

8、参考文档

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html#date-histogram-missing-value
  2. https://www.pipiho.com/es/7.7/cn/search-aggregations-bucket-datehistogram-aggregation.html

正文完
 0