天天看點

Elasticsearch 字段膨脹不要怕,Flattened 類型解千愁!

2、Elasticsarch 字段膨脹

Elasticsearch Mapping 如果不做特殊設定,預設為 dynamic。dynamic 的本質就是:不加限制的動态添加字段。這樣對某些日志場景,可能會産生大量的未知字段。字段如果持續激增,就會達到 Elasticsearch Mapping 層面的預設上限,對應設定和預設大小為:index.mapping.total_fields.limit:1000。

我們把這種非預期字段激增的現象或結果稱為:字段膨脹。

拿自己線上環境示例,說一下 dynamic 的副作用。在一個實際業務環境,混淆了檢索和寫入的文法,會導緻将檢索語句動态認定為新增 Mapping 字段。

當然,如果是非常複雜的大 bool 檢索語句,會導緻 Mapping 變得非常複雜甚至會出現字段膨脹的情況。

Elasticsearch 字段膨脹不要怕,Flattened 類型解千愁!

當然,可行的解決方案就是:dynamic 設定為 false,甚至更為嚴謹的推薦方式:将 dynamic 設定為 strict。

2.1 解決字段膨脹方案一:dynamic 設定為 false

dynamic 設定為 false 後,新來的非 mapping 預設字段資料可以寫入,但是:不能被檢索,僅支援 Get 擷取文檔的方式通過 _source 檢視詳情内容。

舉例如下:

Elasticsearch 字段膨脹不要怕,Flattened 類型解千愁!

2.2 解決字段膨脹方案二:dynamic 設定為 strict

dynamic 一旦設定為:strict,會“阻止一切來犯之敵”,一切索引建立階段指定的 Mapping 字段之外的字段名稱都将會報錯。

設定為 strict 後,再動态插入資料,會報錯如下:

{

 "error" : {

   "root_cause" : [

     {

       "type" : "strict_dynamic_mapping_exception",

       "reason" : "mapping set to strict, dynamic introduction of [cont] within [_doc] is not allowed"

     }

   ],

   "type" : "strict_dynamic_mapping_exception",

   "reason" : "mapping set to strict, dynamic introduction of [cont] within [_doc] is not allowed"

 },

 "status" : 400

}

3、Flattened  類型産生的背景

如前分析,将 dynamic 設定為 false 或者 strict 不是普适的解決方案 ,如日志場景需求如下:

一方面:期望能動态添加字段。strict 過于嚴謹會導緻新字段資料拒絕寫入,dynamic 過于松散會字段膨脹。

另一方面:不期望索引字段膨脹。

這就導緻同時滿足上述兩個方面的 Flattend 字段的誕生。

Flattened  中文釋義:“壓扁、弄平”,實際就是字段扁平化的意思。

當面臨處理包含大量不可預測字段的文檔時,使用 Flattend 類型可以通過将整個 JSON 對象及其嵌套 Nested 字段索引為單個關鍵字 keyword 類型字段來幫助減少字段總數。

Flattened 類型的最早釋出在:7.3 版本。

4、Flattened 類型解決的根本問題

特定日志場景、電商場景,Elasticsearch Mapping 字段數有時是無法預知的。如果随着新寫入資料激增,字段也激增,可能帶來的後果是什麼呢?

Elasticsearch 必須為每個新字段更新叢集狀态,并且必須将此叢集狀态傳遞給所有節點。由于跨節點的叢集狀态傳輸是單線程操作,是以需要更新的字段映射越多,完成更新所需的時間就越長。這種延遲通常大大降低叢集性能,有時會導緻整個叢集當機。這被稱為“ Mapping 爆炸”(mapping explosion)。

這也是 Elasticsearch 從 5.x 及更高版本将索引中的字段數限制為 1000 的原因之一。如果實戰業務場景字段數超過 1000,我們必須手動更改預設索引字段限制或者重新考慮架構重構。

修改預設值的方式如下:

PUT record_infos

 "settings": {

   "index.mapping.total_fields.limit": 2000

 }

Flattened  扁平化字段就是解決:“Mapping 爆炸”問題的。

5、Flattened  類型實戰解讀

5.1 Flattened  類型真容

千呼萬喚始出來,Flattend 真容如下:

Elasticsearch 字段膨脹不要怕,Flattened 類型解千愁!

這和 Integer、long、nested、join 等都屬于字段類型的範疇。

Flattened  本質是:将原來一個複雜的 Object 或者 Nested 嵌套多字段類型統一映射為偏平的單字段類型。

這裡要強調的,不管原來内嵌多少個字段,内嵌多少層,有了 Flattend,一下都打平!!

5.2 基于 Flattened 類型插入資料

基于上面的 Mapping,寫入一條資料如下:

PUT demo-flattened/_doc/1

 "message": "[5592:1:0309/123054.737712:ERROR:child_process_sandbox_support_impl_linux.cc(79)] FontService unique font name matching request did not receive a response.",

 "fileset": {

   "name": "syslog"

 "process": {

   "name": "org.gnome.Shell.desktop",

   "pid": 3383

 "@timestamp": "2020-03-09T18:00:54.000+05:30",

 "host": {

   "hostname": "bionic",

   "name": "bionic"

這時候再檢視 Mapping, 如下:

Elasticsearch 字段膨脹不要怕,Flattened 類型解千愁!

由于 host 字段設定為:Flattened,其下的:hostname、name 字段都不再映射為特定嵌套子字段。

5.3 更新 Flattened 字段,添加資料

POST demo-flattened/_update/1

 "doc": {

   "host": {

     "osVersion": "Bionic Beaver",

     "osArchitecture": "x86_64"

   }

再次檢視 Mapping,依然“巋然不動”。繼續 Flattened 拉平,沒有字段擴增,也就不會再有 “Mapping 爆炸”出現。

5.4 Flattened 類型檢索

以下兩種檢索都會召回資料:

GET demo-flattened/_search

 "query": {

   "term": {

     "host": "Bionic Beaver"

     "host.osVersion": "Bionic Beaver"

而,如下的檢索,則傳回結果為空。

   "match": {

     "host.osVersion": "bionic beaver"

     "host.osVersion": "Beaver"

為什麼呢?

由于使用 Flattened 扁平化類型,Elasticsearch 未對該字段進行分析,是以它隻會傳回比對字母大小寫且完全一緻的結果。

如上檢索結果和 keyword 類型檢索結果一緻。

這也初步暴露出:Flattened 類型的部分缺陷。

5.5 Flattend 類型的不足

每當面臨 Flattened 扁平化對象的決定時,在選型 Elasticsearch 扁平化資料類型時,我們需要考慮以下幾個關鍵限制:

Flattened 類型支援的查詢類型目前僅限于以下幾種:

term

terms

terms_set

prefix

range

match and multi_match

query_string and simple_query_string

exists

Flattened 不支援的查詢類型如下:

無法執行涉及數字計算的查詢,例如:range query。

無法支援高亮查詢。

盡管支援諸如 term 聚合之類的聚合,但不支援處理諸如“histograms”或“date_histograms”之類的數值資料的聚合。

6、小結

Flattened 類型的出現,解決了字段膨脹引起的 Mapping 爆炸問題,如果您的生産環境高于7.3版本,有文章開頭類似問題,可以小心求證、大膽嘗試這種新類型。

您生産環境使用 Flattened 類型了嗎?您有沒有遇到過字段膨脹或“Mapping 爆炸”問題,是如何解決的?

歡迎留言說一下您的實戰思考!

ps:文章标題靈感起源于球友微信交流,對球友表示感謝!

參考

https://coralogix.com/blog/flattened-datatype-mappings-elasticsearch-tutorial/ https://www.elastic.co/guide/en/elasticsearch/reference/master/flattened.html#flattened