2、Elasticsarch 字段膨脹
Elasticsearch Mapping 如果不做特殊設定,預設為 dynamic。dynamic 的本質就是:不加限制的動态添加字段。這樣對某些日志場景,可能會産生大量的未知字段。字段如果持續激增,就會達到 Elasticsearch Mapping 層面的預設上限,對應設定和預設大小為:index.mapping.total_fields.limit:1000。
我們把這種非預期字段激增的現象或結果稱為:字段膨脹。
拿自己線上環境示例,說一下 dynamic 的副作用。在一個實際業務環境,混淆了檢索和寫入的文法,會導緻将檢索語句動态認定為新增 Mapping 字段。
當然,如果是非常複雜的大 bool 檢索語句,會導緻 Mapping 變得非常複雜甚至會出現字段膨脹的情況。

當然,可行的解決方案就是:dynamic 設定為 false,甚至更為嚴謹的推薦方式:将 dynamic 設定為 strict。
2.1 解決字段膨脹方案一:dynamic 設定為 false
dynamic 設定為 false 後,新來的非 mapping 預設字段資料可以寫入,但是:不能被檢索,僅支援 Get 擷取文檔的方式通過 _source 檢視詳情内容。
舉例如下:
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 真容如下:
這和 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, 如下:
由于 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