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

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

摘要

如果说搜索是 Elasticsearch 里最受欢迎的功能,那么按时间创建直方图一定排在第二位。为什么需要使用时间直方图?

版本

elasticsearch版本: elasticsearch-2.x

内容

如果说搜索是 Elasticsearch 里最受欢迎的功能,那么按时间创建直方图一定排在第二位。为什么需要使用时间直方图?

假设我们的数据都有时间戳,无论我们的数据是 Apache 日志事件,或是股票交易日期,还是棒球赛时间,任何与时间戳有关的数据都可以从时间直方图里得到有价值的信息。通常我们希望根据时间来创建度量:

  • 本年度每月汽车销量是多少?
  • 过去 12 小时股价的变化?
  • 过去一周中网站每小时内的平均响应时延是多少?

普通的直方图通常以条状图表表示,日期直方图则会转换成折线图用来表示时间序列。很多公司使用 Elasticsearch 只为了分析时间序列信息。date_histogram 桶正是我们想要的油条和豆浆。

date_histogram 与一般直方图的工作方式类似,不同的是它没有基于数值字段表示数值区间,而是基于时间范围创建桶。因此,每个桶代表时间轴上的一段(比如:1 月 或 2.5 天)。

普通的直方图可以展示时间吗?

技术上讲是可以的。一个普通的直方图桶可以展示时间,但是它并不没有与日历相关的概念。运用 date_histogram,我们可以指定间隔为 1 月,这样我们可以知道二月比十二月的时间短。date_histogram 还有一个优势就是它可以与时区联用,这让我们可以按照用户所处时区来定制图形
报表,而不是服务器时间。

普通的直方图将时间解释成数字,这意味着我们必须以毫秒为单位指定间隔。这样聚合对日历时间间隔没有任何概念,也无法使用日期信息。

我们第一个示例会创建一个简单的折线图表来回答问题:每个月的汽车销量是多少?

  GET /cars/transactions/_search
  {
     "size" : 0,
     "aggs": {
        "sales": {
           "date_histogram": {
              "field": "sold",
              "interval": "month", #1
              "format": "yyyy-MM-dd" #2
           }
        }
     }
  }

#1 这个间隔是日历语境下的值(例如:每个桶表示一个月)。

#2 为其提供一个时间格式这样能显示的更好看。

我们的查询有单个聚合,每个月创建一个桶,为我们提供每月汽车销售的数量。加上 format 参数可以让桶的键值更“好看”。在内部,日期是以简单数字形式表示的,这会让 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

返回空桶(Returning Empty Buckets)

注意到响应中有什么奇怪的吗?

对,正是这样。我们缺失了一些月份的信息,date_histogram(普通 histogram 也是如此)只返回文档数目非零的那些桶。

这表示直方图以最小形式作为响应结果。通常,这并不是我们想要的行为。在很多应用中,我们希望直接将响应数据传入图形库而不要做任何后续处理。

本质上说,即使数目为零我们也希望桶的信息能出现在结果中,可以设置两个参数来实现这个行为:

  GET /cars/transactions/_search
  {
     "size" : 0,
     "aggs": {
        "sales": {
           "date_histogram": {
              "field": "sold",
              "interval": "month",
              "format": "yyyy-MM-dd",
              "min_doc_count" : 0, #1
              "extended_bounds" : { #2
                  "min" : "2014-01-01",
                  "max" : "2014-12-31"
              }
           }
        }
     }
  }

#1 参数强制返回空桶。

#2 参数强制返回全年数据。

两个附加的参数会强制响应返回全年所有月份的信息,无论它们文档数目如何。min_doc_count 哼容易理解:即使桶是空的也会强制作为结果返回。

需要对 extended_bounds 参数做些许解释。 min_doc_count 参数强制空桶信息返回,但是 Elasticsearch 默认只会返回处于最小与最大值之间的数据。

所以如果数据在四月和七月之间,我们的桶只会表示这之间的月份(无论是不是空)。为了得到全年的信息,我们需要告诉 Elasticsearch 我们想要得到那些处于最小值和最大值之外的桶的信息。

extended_bounds 参数就是做这件事情,一旦我们增加了这两个设置,我们就能得到可以直接传入图形库的输出,图形的显示如图 Figure 37, “Cars sold over time”.

Figure 37. Cars sold over time

示例扩展(Extended Example)

正如无数次见到的那样,可以嵌套使用桶获得更复杂的行为。为了举例说明,我们可以创建一个聚合按季度展示所有汽车品牌总销售额,同时按季度、按每个汽车品牌计算销售总额,这样我们就能知道哪种车型能为我们的生意带来更多收益:

  GET /cars/transactions/_search
  {
     "size" : 0,
     "aggs": {
        "sales": {
           "date_histogram": {
              "field": "sold",
              "interval": "quarter", #1
              "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" } #2
                    }
                 }
              },
              "total_sum": {
                 "sum": { "field": "price" } #3
              }
           }
        }
     }
  }

#1 注意我们将间隔从 month 改成了 quarter

#2 按汽车品牌分别求和。

#3 所有汽车品牌总和。

响应返回(结果的少量片段):

  {
  ....
  "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
                       }
                    }
                 ]
              }
           },
  ...
  }

我们将响应的结果作为图形的输入,展现总售价的折线图,并按季度显示每个汽车品牌的销售总额,如图 Figure 38, “Sales per quarter, with distribution per make”

Figure 38. Sales per quarter, with distribution per make

有限空间(The Sky’s the Limit)

这些都是显而易见的简单示例,但是要用图表表示聚合总会有所限制。例如,Figure 39, “Kibana—a real time analytics dashboard built with aggregations” 图中呈现了 Kibana 的一个仪表盘里面展示了丰富的合信息。

Figure 39. Kibana—a real time analytics dashboard built with aggregations

因为聚合的实时性,它们易于查询、处理和交互。这对于非技术员工和分析师来说是理想的工具,因为他们可以分析数据,而知道如何创建 Hadoop 任务。

要创建像 Kibana 这样的强大仪表盘,可能需要理解一些更高级的概念比如:限定范围、过滤以及聚合排序。

参考

elastic.co:
Looking at Time

posted @ 2016-03-24 11:14  Richaaaard  阅读(6134)  评论(0编辑  收藏  举报