# 日期直方图聚合(Date Histogram Aggregation)

与直方图类似的多bucket聚合，但只能应用于日期值.

由于日期在elastic search中以内部值表示,也可以在日期上使用正常的直方图，尽管精度会受到影响(想想闰年和一个月的天数)。因此，我们需要对基于时间的数据进行特殊的支持。从功能的角度来看，该直方图支持与正常[直方图](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html)相同的特征， 主要区别是间隔可以通过日期/时间表达式指定。

要求一个月的间隔时间的bucket：

```
POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "month"
            }
        }
    }
}
```

对于时间间隔，有一下可用表达式：`year`, `quarter`, `month`, `week`, `day`, `hour`, `minute`, `second`

时间值也可以通过 [time units](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units) parsing（时间单元解析）支持的缩写来指定，这里要注意，不支持小数时间值，但是您可以通过转换到另一个时间单位来解决这个问题（例如，1.5h可以被指定为90m）

```
POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "90m"
            }
        }
    }
}
```

## Keys <a href="#datehistogramaggregation-keys" id="datehistogramaggregation-keys"></a>

在内部，日期被表示为64位数，表示时间戳，以毫秒为单位。这些时间戳作为bucket的key（键）返回，key\_as\_string是使用**format**参数指定的格式转换为格式化日期字符串的同一时间戳。

> 如果没有指定**format**，那么它将使用字段映射中指定的第一个日期格式。

```
POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "1M",
                "format" : "yyyy-MM-dd" #1
            }
        }
    }
}
```

| 1 | 支持表达式的日期[format pattern](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html#date-format-pattern)(格式模式) |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

返回结果：

```
{
    ...
    "aggregations": {
        "sales_over_time": {
            "buckets": [
                {
                    "key_as_string": "2015-01-01",
                    "key": 1420070400000,
                    "doc_count": 3
                },
                {
                    "key_as_string": "2015-02-01",
                    "key": 1422748800000,
                    "doc_count": 2
                },
                {
                    "key_as_string": "2015-03-01",
                    "key": 1425168000000,
                    "doc_count": 2
                }
            ]
        }
    }
}
```

## Time Zone <a href="#datehistogramaggregation-timezone" id="datehistogramaggregation-timezone"></a>

日期时间以UTC为单位存储在elastic search中, 默认情况下，所有的bucketing (加权) 和 rounding(舍入)都是以UTC为单位，bucketing要使用不同的时区，可以使用**time\_zone**参数来表示。

时区可以指定为ISO 8601 UTC偏移量 (例如 +01：00或-08：00), 或者作为时区id，在TZ数据库中使用的标识符，如America / Los\_Angeles

请考虑以下示例:

```
PUT my_index/log/1?refresh
{
  "date": "2015-10-01T00:30:00Z"
}

PUT my_index/log/2?refresh
{
  "date": "2015-10-01T01:30:00Z"
}

GET my_index/_search?size=0
{
  "aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day"
      }
    }
  }
}
```

如果没有指定时区，则使用UTC，这将导致这两份文件都被放在同一天的bucket(桶)中，这将于2015年10月1日午夜开始。

```
{
  ...
  "aggregations": {
    "by_day": {
      "buckets": [
        {
          "key_as_string": "2015-10-01T00:00:00.000Z",
          "key":           1443657600000,
          "doc_count":     2
        }
      ]
    }
  }
}
```

如果指定了-01：00的time\_zone的时区，则午夜从UTC之前的一小时开始：

```
GET my_index/_search?size=0
{
  "aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day",
        "time_zone": "-01:00"
      }
    }
  }
}
```

现在，第一份文件落在2015年9月30日bucket(桶)中，而第二份文件则落在了2015年10月1日的bucket(桶)里:

```
{
  ...
  "aggregations": {
    "by_day": {
      "buckets": [
        {
          "key_as_string": "2015-09-30T00:00:00.000-01:00", #1
          "key": 1443574800000,
          "doc_count": 1
        },
        {
          "key_as_string": "2015-10-01T00:00:00.000-01:00", #2
          "key": 1443661200000,
          "doc_count": 1
        }
      ]
    }
  }
}
```

\#1 key\_as\_string值代表指定时区的每一天的午夜。

\#2

> 当使用遵循DST（夏令时）的时区变化时,当这些变化发生的时候，bucket(桶)的大小与使用间隔时所期望的大小略有不同。例如，考虑在CET时区的DST开始：2016年3月27日凌晨2点，时钟转到1小时到当地时间3点。 当使用日期作为间隔时，当天的bucket将只保存23小时的数据而不是其他桶的24小时，对于较短的时间间隔(例如，12h)也是如此。在3月27日上午，当DST转移发生时，我们只有一个11小时的bucket(桶)

## Offset <a href="#datehistogramaggregation-offset" id="datehistogramaggregation-offset"></a>

offset参数通过指定的正(+)或负偏移(-)持续时间来改变每个bucket的开始值，比如1h表示一小时，1d表示一天。有关更多可能的持续时间选项，请参阅“[Time units](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units)”一节

例如，当使用一天的间隔时，每个桶从午夜持续到午夜。将偏移量设置为+ 6h，将会改变每个**bucket(**&#x6876;)的运行时间从早上6点到6点

```
PUT my_index/log/1?refresh
{
  "date": "2015-10-01T05:30:00Z"
}

PUT my_index/log/2?refresh
{
  "date": "2015-10-01T06:30:00Z"
}

GET my_index/_search?size=0
{
  "aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day",
        "offset":    "+6h"
      }
    }
  }
}
```

而不是从午夜开始的一个单独的bucket(桶)，上面的请求将文件从早上6点开始放到bucket(桶)里:

```
{
  ...
  "aggregations": {
    "by_day": {
      "buckets": [
        {
          "key_as_string": "2015-09-30T06:00:00.000Z",
          "key": 1443592800000,
          "doc_count": 1
        },
        {
          "key_as_string": "2015-10-01T06:00:00.000Z",
          "key": 1443679200000,
          "doc_count": 1
        }
      ]
    }
  }
}
```

> 每个bucket(桶)的开始偏移量是在完成time\_zone调整后计算的。

## Keyed Response <a href="#datehistogramaggregation-keyedresponse" id="datehistogramaggregation-keyedresponse"></a>

将keyed标志设置为true会将一个惟一的字符串键与每个bucket关联起来，并将范围作为散列而不是数组返回:

```
POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "1M",
                "format" : "yyyy-MM-dd",
                "keyed": true
            }
        }
    }
}
```

响应结果：

```
{
    ...
    "aggregations": {
        "sales_over_time": {
            "buckets": {
                "2015-01-01": {
                    "key_as_string": "2015-01-01",
                    "key": 1420070400000,
                    "doc_count": 3
                },
                "2015-02-01": {
                    "key_as_string": "2015-02-01",
                    "key": 1422748800000,
                    "doc_count": 2
                },
                "2015-03-01": {
                    "key_as_string": "2015-03-01",
                    "key": 1425168000000,
                    "doc_count": 2
                }
            }
        }
    }
}
```

## Scripts <a href="#datehistogramaggregation-scripts" id="datehistogramaggregation-scripts"></a>

像正常的[直方图](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html)一样，支持文档级脚本和值级脚本，还可以使用order设置来控制返回的bucket的顺序，并根据min\_doc\_count设置对返回的bucket进行筛选(默认情况下，与文档匹配的第一个存储桶与最后一个之间的所有存储桶都将被返回）,该直方图还支持extended\_bounds设置，这使得能够将直方图的范围扩展到数据本身之外(想了解更多关于为什么要这么做的原因请参考[这里](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html#search-aggregations-bucket-histogram-aggregation-extended-bounds)的解释)

## Missing value <a href="#datehistogramaggregation-missingvalue" id="datehistogramaggregation-missingvalue"></a>

**missing**参数定义了如何处理缺少值的文档。默认情况下，它们将被忽略，但也可以将它们视为具有值

```
POST /sales/_search?size=0
{
    "aggs" : {
        "sale_date" : {
             "date_histogram" : {
                 "field" : "date",
                 "interval": "year",
                 "missing": "2000/01/01" #1
             }
         }
    }
}
```

\#1 在publish\_date字段中没有值的文档将与具有值2000-01-01的文档落在同一个存储区中。
