• Elasticsearch 8.X 防止 Mapping “爆炸”的三种方案


    1、什么是 Mapping “爆炸”?

    Elasticsearch 映射如果不做特殊处理,默认 dynamic 为 true。dynamic 为 true 的确切含义是:根据导入的数据自定识别字段类型(有可能不精确),也就是说,可以提前不指定 Mapping,也能写入数据。

    但,这导致的问题也非常明显。Mapping 字段越多,会超过默认字段数上限。超过上限后会导致性能下降和内存问题,特别是在高负载或资源有限的集群中表现更为突出。

    举例:index.mapping.total_fields.limit 限制的默认最大字段数为 1000。

    2、Mapping “爆炸”带来的问题?

    之前被问过类似的问题:

    “博主,我们现在的业务场景是在宽表中,2000+个字段的联合查询,但是es默认单个索引的字段数是1000个,过多会导致内存问题,和es的性能问题,该如何解决这样的场景呢?”

    如下所示,如果任由“sub_field”字段扩展,就会导致 Mapping “爆炸”。

    1. POST dynamic-mapping-test/_doc
    2. {
    3.   "message""hello",
    4.   "transaction": {
    5.     "user""hey",
    6.     "amount"3.14,
    7.     "field3""hey there, new field",
    8.     "field4": {
    9.       "sub_user""a sub field",
    10.       "sub_amount""another sub field",
    11.       "sub_field3""yet another subfield",
    12.       "sub_field4""yet another subfield",
    13.       "sub_field5""yet another subfield",
    14.       "sub_field6""yet another subfield",
    15.       "sub_field7""yet another subfield",
    16.       "sub_field8""yet another subfield",
    17.       "sub_field9""yet another subfield",
    18.       "sub_fieldx""yet another subfield"
    19.     }
    20.   }
    21. }

    实际业务中不见得所有的字段都需要检索和聚合操作,但如上所有字符串类型都被映射为 “text” 和 “keyword” 组合类型。

    我们将浪费内存和磁盘空间来存储这些字段,极大可能这些字段中的某些字段从未被使用过,它们存在的目的仅是:"万一 "它们需要被用于搜索。

    3、如何避免 Mapping "爆炸"?

    第一:业务层面要尽可能的梳理清楚需求,尽可能避免后期的需求变更导致的 Mapping 的大改。

    第二:技术层面要贴合业务需求,合理、规范、站在未来用户使用的角度建模。

    3.1 方案一:设置 dynamic 为 strict

    dynamic 一旦设置为 strict,就意味着只要字段不在初始设定的范围内,就禁止写入。这是最严格的 Mapping 控制策略。

    举例,如下的索引创建dynamic 设置为 strict,而后导入了预制 Mapping 中没有的字段 “field3”。

    1. DELETE dynamic-mapping-test
    2. PUT dynamic-mapping-test
    3. {
    4.  "mappings": {
    5.    "dynamic""strict",
    6.    "properties": {
    7.      "message": {
    8.        "type""text"
    9.      },
    10.      "transaction": {
    11.        "properties": {
    12.          "user": {
    13.            "type""keyword"
    14.          },
    15.          "amount": {
    16.            "type""long"
    17.          }
    18.        }
    19.      }
    20.    }
    21.  }
    22. }
    23. POST dynamic-mapping-test/_doc
    24. {
    25.   "message""hello",
    26.   "transaction": {
    27.     "user""hey",
    28.     "amount"3.14,
    29.     "field3""hey there, new field"
    30.   }
    31. }

    写入 “field3”会报错如下:

    c586a2b22dca209a746a05f844674fe6.png

    "dynamic:strict" 应用场景

    确定业务层面 Mapping 一经敲定,后面不再修改,则可大胆使用 strict。

    这对业务层面、需求层面要求非常高!

    3.2 方案二:设置 dynamic 为 false

    如果 dynamic 设置为 true 代表很“宽泛”的要求;dynamic 设置为 strict 代表很‘’严格”近乎苛刻的要求。

    则,dynamic 设置为 false 则代表介于两者中间的要求。

    如下所示,批量写入数据的时候,写入了 mapping 中没有的字段 title。

    1. PUT dynamic-mapping-disabled
    2. {
    3.   "mappings": {
    4.     "dynamic""false",
    5.     "properties": {
    6.       "message": {
    7.         "type""text"
    8.       }
    9.     }
    10.   }
    11. }
    12. POST dynamic-mapping-disabled/_bulk
    13. {"index":{"_id":1}}
    14. {"title":"elasticsearch is very good!"}

    写入不会报错。但写入后查看一下 Mapping。

    GET dynamic-mapping-disabled/_mapping
    089b1b3a15320cf804cf945277f5e900.png

    执行检索和聚合操作如下,检索和聚合均没有任何数据召回。

    1. ## 如下查询,没有任何数据召回!
    2. POST dynamic-mapping-disabled/_search
    3. {
    4.   "query": {
    5.     "match": {
    6.       "title""good"
    7.     }
    8.   }
    9. }
    10. ## 如下聚合,没有任何数据召回
    11. POST dynamic-mapping-disabled/_search
    12. {
    13.   "size":0,
    14.   "aggs": {
    15.     "terms_aggs": {
    16.       "terms": {
    17.         "field""title",
    18.         "size"10
    19.       }
    20.     }
    21.   }
    22. }

    "dynamic:false" 应用场景

    当设置 dynamic 为 false 时,非 Mapping 指定的字段数据,如上“title”也可以写入索引。但,并没有建立倒排索引和正排索引,也就是说,不会被检索和聚合召回。仅在_source 中被召回显示。这些字段仅会浪费磁盘空间,不会占据内存空间。

    POST dynamic-mapping-disabled/_search
    3fa3fccaccad975f700fbd14aaed6399.png

    3.3 方案三:设置 dynamic 为 runtime(运行时字段类型)

    之前咱们已经过 runtime field 的来龙去脉。

    如果把没有 runtime field 之前的 Mapping 叫做 shema on write,那么 runtime field 革命性创新在与其是 schema on read。

    runtime field 的本质是:不会在新字段上浪费内存存储,但我们要付出查询或聚合操作响应速度变慢的代价。

    仍拿之前的索引和数据为例。

    1. DELETE dynamic-mapping-runtime
    2. PUT dynamic-mapping-runtime
    3. {
    4.  "mappings": {
    5.    "dynamic""runtime",
    6.    "properties": {
    7.      "message": {
    8.        "type""text"
    9.      },
    10.      "transaction": {
    11.        "properties": {
    12.          "user": {
    13.            "type""keyword"
    14.          },
    15.          "amount": {
    16.            "type""long"
    17.          }
    18.        }
    19.      }
    20.    }
    21.  }
    22. }
    23. POST dynamic-mapping-runtime/_doc
    24. {
    25.  "message""hello",
    26.  "transaction": {
    27.    "user""hey",
    28.    "amount"3.14,
    29.    "field3""hey there, new field",
    30.    "field4": {
    31.      "sub_user""a sub field",
    32.      "sub_amount""another sub field",
    33.      "sub_field3""yet another subfield",
    34.      "sub_field4""yet another subfield",
    35.      "sub_field5""yet another subfield",
    36.      "sub_field6""yet another subfield",
    37.      "sub_field7""yet another subfield",
    38.      "sub_field8""yet another subfield",
    39.      "sub_field9""yet another subfield"
    40.    }
    41.  }
    42. }
    GET dynamic-mapping-runtime/_mapping

    Mapping 返回如下:

    14dd1070b772d81f740f7ea7ed19b2c1.png

    这些运行时的字段是可以被检索的,举例如下:

    1. POST dynamic-mapping-runtime/_search
    2. {
    3.  "query": {
    4.    "term": {
    5.      "transaction.field4.sub_field6""yet another subfield"
    6.    }
    7.  }
    8. }

    "dynamic:runtime" 应用场景

    当不知道要写入什么类型的文档时,这个策略会很有用!使用运行时字段是一个保守的方法,需要在性能和映射复杂性之间有一个很好的权衡。

    4、小结

    每种方案都有优点,当然也存在不足,我们需要结合自己业务场景仔细斟酌后选型。

    类别优点缺点
    strict字段必须先明确指定非明确指定的字段,禁止写入
    false所有字段均可写入未被映射的字段不能用于搜索或聚合
    runtime更为灵活的方式在查询运行时字段时,搜索响应时间相对较慢,需要做好取舍、权衡利弊

    大家还有没有更好的方案?欢迎留言交流。

     参考&推荐

    1、https://www.elastic.co/cn/blog/3-ways-to-prevent-mapping-explosion-in-elasticsearch

    2Elasticsearch 运行时类型 Runtime fields 深入详解

    3、阿里云大佬叮嘱我务必要科普这个 Elasticsearch API

    4、Elasticsearch 可以更改 Mapping 吗?如何修改?

    65fdb3f935058df5cfd00f86d8b43228.png

    更短时间更快习得更多干货!

    中国50%+Elastic认证专家出自于此!

    在不确定的时代,寻求确定性!

    f3ed089df45b1aa1f13669ff9ee3e01c.gif

    比同事抢先一步学习进阶干货!

  • 相关阅读:
    书写高质量sql的一些建议
    我在VScode学Java(Java方法method)
    袋鼠云平台代码规范化编译部署的提效性改进实践
    代码随想录 动态规划 part16
    模拟实现通讯录的功能(文件版本)
    【React 源码】(十五)React Context 原理
    Windows OpenGL ES 图像透明度
    Python Google内购服务端验证
    测评补单:Temu卖家的市场攻略,轻松吸引更多流量和转化!
    腾讯云双11服务器优惠活动价格表预热!
  • 原文地址:https://blog.csdn.net/wojiushiwo987/article/details/127380795