Elasticsearch学习-ES中动态映射有什么用

在系统开发过程中,,随着业务不断发展和需求的不断迭代,业务系统中的原有数据表结构无法满足现有功能需求,这个时候常用的做法就是修改表结构,增加或者修改原有schema中的字段类型。

与传统关系型数据相比,ES有一个明显的差异,就是可以在原有索引中添加新的字段数据,而无需做其他类似schema的 调整。在关系型数据库中,表结构定义完毕后,只能在表中插入schema中指定的字段信息。而在ES中是可以打破这个限制的。

动态映射

在ES中,这种可以动态添加新字段的能力叫做动态映射。通过 dynamic 属性控制。该属性 可接受的选项如下:

true:动态添加新的字段

false:忽略新的字段

strict:如果遇到新字段抛出异常

配置参数 dynamic 可以用在根 object 或其他object 类型的字段上。这种灵活的配置可以实现不同对象类型中的动态映射能力。

PUT /my_index
{
    "mappings": {
        "my_type": {
            "dynamic":      "strict", 
            "properties": {
                "title":  { "type": "string"},
                "stash":  {
                    "type":     "object",
                    "dynamic":  true 
                }
            }
        }
    }
}

在上述的配置中,类型my_type中不允许添加新的字段,而在内部对象stash 中可以动态创建新字段。

我们尝试给 stash 对象添加新的可检索的字段:

PUT /my_index/my_type/1
{
    "title":   "This doc adds a new field",
    "stash": { "new_field": "new value" }
}

响应如下:

{
  "_index" : "my_index",
  "_type" : "my_type",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "This doc adds a new field",
    "stash" : {
      "new_field" : "new vlaue!"
    }
  }
}

但是对根节点对象 my_type 进行同样的操作会失败:

PUT /my_index/my_type/1
{
    "title":     "This throws a StrictDynamicMappingException",
    "new_field": "Fail!"
}

{
  "error" : {
    "root_cause" : [
      {
        "type" : "strict_dynamic_mapping_exception",
        "reason" : "mapping set to strict, dynamic introduction of [new_field] within [my_type] is not allowed"
      }
    ],
    "type" : "strict_dynamic_mapping_exception",
    "reason" : "mapping set to strict, dynamic introduction of [new_field] within [my_type] is not allowed"
  },
  "status" : 400
}

虽然ES支持动态映射的能力,但是细心的小伙伴可能会有这样一个问题:向原有的索引中添加一个新的字段,ES会将这个字段当做什么类型处理呢? 因为新添加的字段没有在索引的mapping中指定过类型,此时,那就只能依靠ES自身的规则来判断了,但是业务场景是丰富多样的,完全依赖ES的自身"黑盒"规则,是不能满足需求的,这里我们举例说明一下:

当向索引中第一次添加一个新字段note,并指定value是一个字符串:

{ "note": "2022-01-01" }

当在再次添加note数据:

{ "note": "today is 2022-07-23" }

却会报错。这是为什么呢?

当 ES 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2022-01-01 。如果它像日期,这个字段就会被作为 date 类型添加,此时新添加的字段note,就被ES标记为date类型了,那么第二次添加 { “note”: “today is 2022-07-23” }时, 发现 “today is 2022-07-23” 不是date类型,此时就会因为类型不匹配而报错。

由此可见,ES的动态映射在类型判定规则上,不太能够满足业务需求。对于此类问题,ES提供了动态模板,让使用者自定义类型解析规则。

动态模板

使用 dynamic_templates ,可以让我们完全控制生成字段的映射。在动态模板中,可以通过字段名称或数据类型来应用不同的映射。

PUT my_index
{
  "mappings": {
    "my_type": {
      "dynamic_templates": [
        {
          "string2long": {
            "match_mapping_type": "string",
            "mapping": {
              "type": "long"
            }
          }
        }
      ]
    }
  }
}

在上面的动态模板string2long中,使用属性:match_mapping_type 来限制可以使用该模板的新映射:只有sting类型的新映射才可以使用该模板,并且在ES中被映射的类型是long。

PUT my_index/my_type/1
{
  "my_long": "5", 
}

会使用 string2long模板,并将my_long定义为long类型。

但是如果是以下语句就会存在异常:

PUT my_index/my_type/1
{
  "my_string": "abc"
}

因为 "abc"无法被解析成 long类型字段。

上面 match_mapping_type 通过字段类型来控制使用哪个动态模板,在动态模板中match属性,可以根据字段名称来控制使用哪个动态模板:

PUT /my_index
{
    "mappings": {
        "my_type": {
            "dynamic_templates": [
                { "es": {
                      "match":              "*_string", 
                      "mapping": {
                          "type":           "string"
                      }
                      }
                }}
            ]
}}

模板es表示:只有字段类型以"_string"结尾的新映射,才会使用该模板。

其实 match_mapping_typematch 两个属性可以同时使用,同时使用时,只不过加强了使用该模板的限制,只有两个条件都满足的时候,才会使用该模板,除此之外,一个索引可以定义多个动态模板,多个模板之间的优先级为:模板定义的位置顺序,定义靠前的优先级更高。

PUT /my_index
{
    "mappings": {
            "dynamic_templates": [
                { "es": {
                      "match":              "*_es", 
                      "match_mapping_type": "string",
                      "mapping": {
                          "type":           "string",
                          "analyzer":       "spanish"
                      }
                }},
                { "en": {
                      "match":              "*_he", 
                      "match_mapping_type": "long",
                      "mapping": {
                          "type":           "long"
                      }
                }}
            ]
}}

在上面定义中,es模板的优先级高于en。使用es模板的条件为:字段类型以"_es"结尾,同时类型为string;而使用en模板的条件为:字段类型为long,同时字段名称以"_he"结尾的映射。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值