Elasticsearch如何将object类型字段reindex为text类型并解决报错
报错核心原因
你执行原生reindex时触发类型不匹配错误,本质是字段值类型无法直接透传:
- 源索引中
Foo为嵌套object类型,存储值是包含ID、Name结构的JSON对象 - 目标索引中
Foo为text类型,要求输入值为纯文本字符串 - 原生reindex无自动嵌套对象到字符串的转换逻辑,读到对象起始的
{结构标记时,无法将其解析为text字段的合法值,最终触发Can't get text on a START_OBJECT报错。
可落地实现步骤
- 第一步:提前创建目标索引,手动配置映射,不要依赖ES自动映射(避免自动将
Foo识别为object类型),目标映射按你的需求配置即可,示例如下:
PUT /your_target_index { "mappings": { "properties": { "Foo": { "type": "text", "index": "false" } // 其他需要保留的字段按原有映射正常配置即可 } } }
- 第二步:执行reindex任务时,添加转换脚本将原object类型的
Foo值转为字符串后再写入,禁止直接透传对象结构。根据你对字符串内容的需求,可以选择两种脚本逻辑:- 完整保留原对象信息的序列化方案:将原
Foo对象直接转成JSON字符串存入目标字段
对应的完整reindex DSL:
- 完整保留原对象信息的序列化方案:将原
POST _reindex { "source": { "index": "your_source_index" }, "dest": { "index": "your_target_index" }, "script": { "source": """ def fooOrigin = ctx._source.remove("Foo"); if (fooOrigin != null) { ctx._source.Foo = groovy.json.JsonOutput.toJson(fooOrigin); } """ } }
2. 自定义可读文本方案:如果不需要保留JSON结构,可将`ID`、`Name`字段拼接为常规可读文本: 脚本部分调整为:
"script": { "source": """ def fooOrigin = ctx._source.remove("Foo"); if (fooOrigin != null) { ctx._source.Foo = "ID: " + fooOrigin.get("ID", "") + ", Name: " + fooOrigin.get("Name", ""); } """ }
注意事项
- 脚本中通过
remove方法取出原object值后再处理,可避免目标字段出现结构冲突 - 因目标字段配置了
index: false,转换后的字符串仅做文档存储,不会生成倒排索引,无额外索引开销 - 如果源文档量较大,可在reindex请求中添加批次大小、节流参数,避免任务抢占集群资源影响正常业务运行
内容的提问来源于stack exchange,提问作者SuperSonic
相关产品推荐
相关产品推荐

