本章翻譯自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)。