elasticsearch 時間問題


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

  1. GMT:格林威治標准時間 
  2. UTC:世界協調時間 
  3. DST:夏日節約時間 
  4. 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里面有幾個比較重要的參數:

  1.  
    field:指定按那個字段聚合
  2.  
    interval:聚合的時間單位(年,季度,月,周,天,小時,分鍾,秒)
  3.  
    format:日期格式
  4.  
    time_zone:時區指定
  5.  
    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”所對應的時間戳)所對應得時間戳。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM