https://www.cnblogs.com/libin2015/p/9394995.html
Elasticsearch中定義時間的類型為Date
Elasticsearch原生支持date類型,json格式通過字符來表示date類型。所以在用json提交日期至elasticsearch的時候,es會隱式轉換,
把es認為是date類型的字符串直接轉為date類型。至於什么樣的字符串es會認為可以轉換成date類型,參考elasticsearch官網介紹:
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html
date type默認格式:
"strict_date_optional_time||epoch_millis"
date類型是包含時區信息的,如果我們沒有在json代表日期的字符串中顯式指定時區,對es來說沒什么問題,
但是如果通過kibana顯示es里的數據時,就會出現問題,數據的時間會晚8個小時。因為kibana從es里讀取的date類型數據,沒有時區信息,
kibana會默認當作0時區來解析,但是kibana在通過瀏覽器展示的時候,會通過js獲取當前客戶端機器所在的時區,也就是東八區,
所以kibana會把從es得到的日期數據減去8小時。這里就會導致kibana經常遇到的“數據時間延遲8小時”的問題。
所以最佳實踐方案就是:我們在往es提交日期數據的時候,直接提交帶有時區信息的日期字符串,如:“2016-07-15T12:58:17.136+0800”。
##索引中定義的日期格式與提交數據的日期格式要一致,否則會報錯。
創建索引是指定date format示例:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
}
date官網介紹:
https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html
- GMT:格林威治標准時間
- UTC:世界協調時間
- DST:夏日節約時間
- CST:中國標准時間
其中GMT時間可以近似認為和UTC時間是相等的,但從精度上來說UTC時間更精確。其誤差值必須保持在0.9秒以內
CST= GMT + 8 =UTC + 8
從上面可以看出來中國的時間是等於UTC時間+8小時,es默認存儲時間的格式是UTC時間,如果我們查詢es然后獲取時間日期默認的數據,會發現跟當前的時間差8個小時,這其實是正常的,因為es默認存儲是用的UTC時間,所以我們需要做的就是讀取long型時間戳,然后重新格式化成下面的時間戳,即可獲得正確的時間 :
yyyy-MM-dd HH:mm:ss
像差8個時區的事情,最容易見到的就是,我們使用logstash收集的日志,發送到es里面,然后通過head查詢就能發現不一致,但是如果我們用kibana查詢,就不會發現時區問題,為什么? 因為kibana已經處理時區問題了,所以在kibana的頁面顯示的時間是正確的。
此外在使用Java Client聚合查詢日期的時候,需要注意時區問題,因為默認的es是按照UTC標准時區算的,所以不設置的聚合統計結果是不正確的。
在es的DateHistogramBuilder里面有幾個比較重要的參數:
-
field:指定按那個字段聚合
-
interval:聚合的時間單位(年,季度,月,周,天,小時,分鍾,秒)
-
format:日期格式
-
time_zone:時區指定
-
offset:時間偏移量
注意,默認不設置時區參數,es是安裝UTC的時間進行查詢的,所以分組的結果可能與預期不一樣,所以我們要指定時區為Asia/Shanghai代表北京的時區,這樣才能獲取正確的聚合結果
1.1 Date類型數據的存儲
UTC(Universal Time Coordinated) 叫做世界統一時間,中國大陸所用的時間是東8區時間,比UTC時間超前8小時。即與 UTC 的時差是 +8 ,也就是 UTC+8。
在Elasticsearch內部,不論 date 是什么展示格式,所有date類型數據(時間字符串 or 時間戳等)在 Elasticsearch 內部存儲時全部都會轉換成 UTC時間戳(並且把時區也會計算進去),最后以milliseconds-since-the-epoch 作為存儲的格式。
1.2 Date類型數據的查詢
在Elasticsearch內部,date被轉為UTC,並被存儲為一個長整型數字,代表從1970年1月1號0點到現在的毫秒數。
date類型字段上的查詢會在內部被轉為對long型值的范圍查詢,查詢的結果類型是字符串。
-
假如插入的時候,值是
"2018-01-01",則返回"2018-01-01" -
假如插入的時候,值是
"2018-01-01 12:00:00",則返回"2018-01-01 12:00:00" -
假如插入的時候,值是
1514736000000,則返回"1514736000000"。(進去是long型,出來是String型)
在查詢日期時,會執行下面的過程:
- 轉換成
long整形格式的范圍(range) 查詢 - 得到聚合的結果
- 將結果中的
date類型(long整型數據)根據date format字段轉換回對應的展示格式
1.3 Date類型數據的展示
Elasticsearch 數據是以 json格式存儲的,而 json中是並沒有 date 數據類型,因此 Elasticsearch 中雖然有 date 類型,但在展示時卻要轉化成另外的格式。
date 類型在 Elasticsearch 展示的格式有下面幾種:
- 將日期時間格式化后的字符串,如
"2015-01-01"或者"2015/01/01 12:10:30" long型的整數,意義是milliseconds-since-the-epoch,翻譯一下就是自1970-01-01 00:00:00 UTC以來經過的毫秒數。int型的整數,意義是seconds-since-the-epoch,是指自1970-01-01 00:00:00 UTC以來經過的秒數。
當時間字符串中沒有時區信息時,此時,在ES內部會將其(“2019-09-24 00:00:00“)當成是0時區的“2019-09-24 00:00:00”。
而在我們的Java程序中,Date.getTime()所獲取的卻是將其當做是東8區的時間“2019-09-24 00:00:00”(即返回的是北京時間1970年01月1日0點0分0秒以來的毫秒數,對應UTC時間1970年01月1日8點0分0秒以來的毫秒數,其數值大小等於0時區的“2019-09-23 16:00:00”所對應的時間戳)所對應得時間戳。

