本章翻译自Elasticsearch官方指南的Looking at Time一章。html
若是在ES中,搜索是最多见的行为,那么建立日期柱状图(Date Histogram)确定是第二常见的。为何要使用日期柱状图呢?git
想象在你的数据中有一个时间戳。数据是什么不重要-Apache日志事件,股票交易日期,棒球比赛时间-任何拥有时间戳的数据都能经过日期柱状图受益。当你有时间戳时,你常常会想建立基于时间的指标信息:github
今年的每月销售了多少辆车?json
过去的12小时中,这只股票的价格是多少?服务器
上周每一个小时咱们的网站的平均延迟是多少?elasticsearch
常规的histogram一般使用条形图来表示,而date histogram倾向于被装换为线图(Line Graph)来表达时间序列(Time Series)。不少公司使用ES就是为了对时间序列数据进行分析。ide
date_histogram的工做方式和常规的histogram相似。常规的histogram是基于数值字段来建立数值区间的桶,而date_histogram则是基于时间区间来建立桶。所以每一个桶是按照某个特定的日历时间定义的(好比,1个月或者是2.5天)。oop
常规Histogram可以和日期一块儿使用吗?网站
从技术上而言,是能够的。常规的histogram桶能够和日期一块儿使用。可是,它并懂日期相关的信息(Not calendar-aware)。而对于date_histogram,你能够将间隔(Interval)指定为1个月,它知道2月份比12月份要短。date_histogram还可以和时区一同工做,所以你能够根据用户的时区来对图形进行定制,而不是根据服务器。ui
常规的histogram会将日期理解为数值,这意味着你必须将间隔以毫秒的形式指定。同时聚合也不理解日历间隔,因此它对于日期几乎是无法使用的。
第一个例子中,咱们会建立一个简单的线图(Line Chart)来回答这个问题:每月销售了多少辆车?
GET /cars/transactions/_search?search_type=count
{
"aggs": { "sales": { "date_histogram": { "field": "sold", "interval": "month", "format": "yyyy-MM-dd" } } } }
在查询中有一个聚合,它为每月建立了一个桶。它可以告诉咱们每月销售了多少辆车。同时指定了一个额外的格式参数让桶拥有更"美观"的键值。在内部,日期被简单地表示成数值。然而这会让UI设计师生气,所以使用格式参数可让日期以更常见的格式进行表示。
获得的响应符合预期,可是也有一点意外(看看你可以察觉到):
{
...
"aggregations": { "sales": { "buckets": [ { "key_as_string": "2014-01-01", "key": 1388534400000, "doc_count": 1 }, { "key_as_string": "2014-02-01", "key": 1391212800000, "doc_count": 1 }, { "key_as_string": "2014-05-01", "key": 1398902400000, "doc_count": 1 }, { "key_as_string": "2014-07-01", "key": 1404172800000, "doc_count": 1 }, { "key_as_string": "2014-08-01", "key": 1406851200000, "doc_count": 1 }, { "key_as_string": "2014-10-01", "key": 1412121600000, "doc_count": 1 }, { "key_as_string": "2014-11-01", "key": 1414800000000, "doc_count": 2 } ] ... }
聚合完整地被表达出来了。你能看到其中有用来表示月份的桶,每一个桶中的文档数量,以及漂亮的key_as_string。
发如今上面的响应中的奇怪之处了吗?
Yep, that’s right. We are missing a few months! By default, the date_histogram (and histogram too) returns only buckets that have a nonzero document count. 是的,咱们缺失了几个月!默认状况下,date_histogram(以及histogram)只会返回文档数量大于0的桶。
这意味着获得的histogram响应是最小的。可是有些时候该行为并非咱们想要的。对于不少应用而言,你须要将获得的响应直接置入到一个图形库中,而不须要任何额外的处理。
所以本质上,咱们须要返回全部的桶,哪怕其中不含有任何文档。咱们能够设置两个额外的参数来实现这一行为:
GET /cars/transactions/_search?search_type=count
{
"aggs": { "sales": { "date_histogram": { "field": "sold", "interval": "month", "format": "yyyy-MM-dd", "min_doc_count" : 0, "extended_bounds" : { "min" : "2014-01-01", "max" : "2014-12-31" } } } } }
以上的min_doc_count参数会强制返回空桶,extended_bounds参数会强制返回一全年的数据。
这两个参数会强制返回该年中的全部月份,不管它们的文档数量是多少。min_doc_count的意思很容易懂:它强制返回哪怕为空的桶。
extended_bounds参数须要一些解释。min_doc_count会强制返回空桶,可是默认ES只会返回在你的数据中的最小值和最大值之间的桶。
所以若是你的数据分布在四月到七月,你获得的桶只会表示四月到七月中的几个月(可能为空,若是使用了min_doc_count=0)。为了获得一全年的桶,咱们须要告诉ES须要获得的桶的范围。
extended_bounds参数就是用来告诉ES这一范围的。一旦你添加了这两个设置,获得的响应就很容易被图形生成库处理而最终获得下图:
咱们已经看到过不少次,为了实现更复杂的行为,桶能够嵌套在桶中。为了说明这一点,咱们会建立一个用来显示每一个季度,全部制造商的总销售额的聚合。同时,咱们也会在每一个季度为每一个制造商单独计算其总销售额,所以咱们可以知道哪一种汽车创造的收益最多:
GET /cars/transactions/_search?search_type=count
{
"aggs": { "sales": { "date_histogram": { "field": "sold", "interval": "quarter", "format": "yyyy-MM-dd", "min_doc_count" : 0, "extended_bounds" : { "min" : "2014-01-01", "max" : "2014-12-31" } }, "aggs": { "per_make_sum": { "terms": { "field": "make" }, "aggs": { "sum_price": { "sum": { "field": "price" } } } }, "total_sum": { "sum": { "field": "price" } } } } } }
能够发现,interval参数被设成了quarter。
获得的响应以下(删除了不少):
{
....
"aggregations": { "sales": { "buckets": [ { "key_as_string": "2014-01-01", "key": 1388534400000, "doc_count": 2, "total_sum": { "value": 105000 }, "per_make_sum": { "buckets": [ { "key": "bmw", "doc_count": 1, "sum_price": { "value": 80000 } }, { "key": "ford", "doc_count": 1, "sum_price": { "value": 25000 } } ] } }, ... }
咱们能够将该响应放入到一个图形中,使用一个线图(Line Chart)来表达总销售额,一个条形图来显示每一个制造商的销售额(每一个季度),以下所示:
显然它们都是简单的例子,可是在对聚合进行绘图时,是存在无限的可能性的。好比,下图是Kibana中的一个用来进行实时分析的仪表板,它使用了不少聚合:
由于聚合的实时性,相似这样的仪表板是很容易进行查询,操做和交互的。这让它们很是适合非技术人员和分析人员对数据进行分析,而不须要他们建立一个Hadoop任务。
为了建立相似Kibana的强大仪表板,你须要掌握一些高级概念,好比做用域(Scoping),过滤(Filtering)和聚合排序(Sorting Aggregations)。