Elasticsearch 字段膨胀不要怕,Flattened 类型解千愁!
1、线上真实案例
球友问题:我记得您写过一篇关于建模字段膨胀的问题,对于比如request header response这种动态的对象,是怎么处理来着?
进一步反馈:决定升级es高版本了,Flattened 解千愁!主要我们这需求要把接口所有信息都保留,只能这样了。
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
2.2 解决字段膨胀方案二:dynamic 设置为 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
}
}
5、Flattened 类型实战解读
5.1 Flattened 类型真容
5.2 基于 Flattened 类型插入数据
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"
}
}
5.3 更新 Flattened 字段,添加数据
POST demo-flattened/_update/1
{
"doc": {
"host": {
"osVersion": "Bionic Beaver",
"osArchitecture": "x86_64"
}
}
}
5.4 Flattened 类型检索
GET demo-flattened/_search
{
"query": {
"term": {
"host": "Bionic Beaver"
}
}
}
GET demo-flattened/_search
{
"query": {
"term": {
"host.osVersion": "Bionic Beaver"
}
}
}
而,如下的检索,则返回结果为空。
GET demo-flattened/_search
{
"query": {
"match": {
"host.osVersion": "bionic beaver"
}
}
}
GET demo-flattened/_search
{
"query": {
"match": {
"host.osVersion": "Beaver"
}
}
}
5.5 Flattend 类型的不足
term terms terms_set prefix range match and multi_match query_string and simple_query_string exists
无法执行涉及数字计算的查询,例如:range query。 无法支持高亮查询。 尽管支持诸如 term 聚合之类的聚合,但不支持处理诸如“histograms”或“date_histograms”之类的数值数据的聚合。
6、小结
参考
https://coralogix.com/blog/flattened-datatype-mappings-elasticsearch-tutorial/
https://www.elastic.co/guide/en/elasticsearch/reference/master/flattened.html#flattened