Elasticsearch 5.5重索引触发_version映射错误,如何解决?
首先咱们来拆解你遇到的问题:
错误根源
你的核心问题出在源索引A的myobj字段设置了enabled: false——这个配置意味着ES不会索引该字段,但会完整保留_source中的原始内容。如果你的源文档里myobj内部包含了名为_version的业务字段(注意这不是ES的元字段_version),当重索引到目标索引B时,B的myobj默认开启了动态映射(dynamic: true),ES会尝试为myobj._version自动生成映射,但_version是ES的保留元字段名称,无法作为普通字段的类型,因此触发了Cannot generate dynamic mappings of type [_version] for [_version]错误。
而你之前尝试的脚本错误地修改了ES的元字段ctx._version,这直接导致版本冲突:你把业务数据里的_version值赋值给了文档的元版本号,而目标索引B中没有对应版本的文档,因此抛出version conflict错误。
正确的解决方法
下面提供两种可行的方案,你可以根据需求选择:
方案1:修改重索引脚本,清理业务数据中的_version字段
不需要操作ES的元字段,只需要在重索引时移除_source里myobj下的_version键即可:
{ "source": { "index": "a" }, "dest": { "index": "b" }, "script": { "inline": "if (ctx._source.myobj != null) { ctx._source.myobj.remove('_version'); }" } }
这个脚本会检查源文档的myobj字段,如果存在就移除其中的_version键,这样目标索引B就不会尝试为这个保留字段生成映射,重索引就能正常进行。
方案2:修改目标索引B的映射,关闭myobj的动态映射
如果你不需要myobj下除mykey之外的其他字段,可以直接关闭myobj的动态映射,这样ES会自动忽略myobj下未定义的字段(包括_version):
- 先关闭索引B(已存在的索引需要先关闭才能修改映射):
POST /_close/b
- 修改索引B的映射:
PUT /_mapping/b { "myobj": { "_all": {"enabled": false}, "dynamic": false, "properties": { "mykey": {"type": "keyword"} } } }
- 重新打开索引B:
POST /_open/b
之后再执行普通的重索引请求即可:
{ "source": { "index": "a" }, "dest": { "index": "b" } }
为什么之前的尝试无效?
- 添加
conflicts: "proceed"后没有文档被重索引,是因为动态映射的错误在版本冲突之前就发生了,ES根本没有开始处理文档,自然没有冲突可跳过。 - 修改
version_type无法解决问题,因为错误的根源不是元版本号的处理逻辑,而是业务字段名与ES保留字段冲突导致的动态映射失败。
内容的提问来源于stack exchange,提问作者siltalau

