1. 程式人生 > >ElasticSearch6.2.4(17)——時間資料處理(date histogram)

ElasticSearch6.2.4(17)——時間資料處理(date histogram)

時間資料處理(Looking at Time)

如果在ES中,搜尋是最常見的行為,那麼建立日期柱狀圖(Date Histogram)肯定是第二常見的。為什麼要使用日期柱狀圖呢?

想象在你的資料中有一個時間戳。資料是什麼不重要-Apache日誌事件,股票交易日期,棒球比賽時間-任何擁有時間戳的資料都能通過日期柱狀圖受益。當你有時間戳時,你經常會想建立基於時間的指標資訊:

  • 今年的每個月銷售了多少輛車?

  • 過去的12小時中,這隻股票的價格是多少?

  • 上週每個小時我們的網站的平均延遲是多少?

常規的histogram通常使用條形圖來表示,而date histogram傾向於被裝換為線圖(Line Graph)來表達時間序列(Time Series)。很多公司使用ES就是為了對時間序列資料進行分析。

date_histogram的工作方式和常規的histogram類似。常規的histogram是基於數值欄位來建立數值區間的桶,而date_histogram則是基於時間區間來建立桶。因此每個桶是按照某個特定的日曆時間定義的(比如,1個月或者是2.5天)。

常規Histogram能夠和日期一起使用嗎?

從技術上而言,是可以的。常規的histogram桶可以和日期一起使用。但是,它並懂日期相關的資訊(Not calendar-aware)。而對於date_histogram,你可以將間隔(Interval)指定為1個月,它知道2月份比12月份要短。date_histogram還能夠和時區一同工作,因此你可以根據使用者的時區來對圖形進行定製,而不是根據伺服器。

常規的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)。

--------------------- 本文來自 dm_vincent 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/dm_vincent/article/details/42594043?utm_source=copy