bigywater.tech
Elasticsearch · 20

Reindex 如何迁移 Mapping

真实尝试原地修改已存在字段的类型被拒绝后,用_reindex把数据搬到Mapping正确的新索引,顺带踩中一个reindex完立刻查count却是0的真实的坑。

原地改字段类型
真实400拒绝,text不能变成keyword
_reindex完立刻_count
真实是0,没有自动refresh
refresh后term精确查询
真实命中,keyword类型的效果生效了

做的事:真实先确认字段类型不能原地改,再用_reindex搬到一个Mapping正确的新索引

代码PUT /reindex_src {"mappings": {"properties": {"zipcode": {"type": "text"}}}} POST .../_doc/1 {"zipcode": "02139"} POST .../_doc/2 {"zipcode": "10001"} PUT /reindex_src/_mapping {"properties":{"zipcode":{"type":"keyword"}}} # 原地改类型 PUT /reindex_dst {"mappings": {"properties": {"zipcode": {"type": "keyword"}}}} POST /_reindex {"source": {"index": "reindex_src"}, "dest": {"index": "reindex_dst"}}

验证:原地修改已存在字段的类型,真实直接400拒绝

实测 · 本机 Elasticsearch 8.15.0 执行输出
PUT /reindex_src/_mapping {"properties":{"zipcode":{"type":"keyword"}}}
→ 400 illegal_argument_exception:
  "mapper [zipcode] cannot be changed from type [text] to [keyword]"

这条真实报错呼应了本系列前面验证过的"字段类型一旦建立后为什么不能随便修改"——text和keyword在Lucene底层真实对应完全不同的索引结构(text真实存的是分词后的倒排索引,keyword存的是整个值不分词的倒排索引),已经写入的文档,它们的倒排索引真实是按照创建时的类型建好的,没有办法原地"重新按另一种方式建索引"——哪怕索引里当前一条数据都没有,ES也真实不允许这种类型变更,必须创建一个新的索引。

验证:_reindex真实把数据从旧索引完整搬进了Mapping正确的新索引

实测 · 本机执行输出
POST /_reindex {"source":{"index":"reindex_src"},"dest":{"index":"reindex_dst"}}
→ {"total": 2, "created": 2, "failures": []}    ← 真实2条数据都成功搬过去了

GET /reindex_dst/_count (紧接着立刻查)
→ {"count": 0}    ← 真实是0!明明reindex响应说created:2了

手动refresh之后再查:
GET /reindex_dst/_count → {"count": 2}   ← 这次真实对了
这是本文真实踩到的一个容易让人虚惊一场的坑:_reindexAPI真实跟普通的_doc写入一样,完成写入之后不会主动触发refresh,新写入的文档虽然真实已经进了Lucene的内存缓冲区,但要等到下一次这个索引的自动刷新周期(默认1秒)到了、或者手动调用一次_refresh,才会真实变得可被搜索到。_reindex响应里的created: 2是真实准确的——数据确实写进去了,但"写进去"和"能被搜到"在ES里真实是两个独立的时间点(这正是本系列前面专门验证过的ES为什么是"近实时"系统的同一套机制),如果reindex完立刻去查count或者做验证,真实很容易被这个瞬间的0值误导,以为数据丢了。

验证:reindex之后,原来text类型做不到的精确匹配真实可以了

实测 · 本机执行输出
GET /reindex_dst/_search {"query":{"term":{"zipcode":"02139"}}}
→ hits.total.value = 1    ← 真实命中了,这是keyword类型精确匹配的真实效果

这条真实结果证明了整个reindex流程确实达到了目的:新索引里的zipcode字段真实变成了keyword类型,term这种要求精确匹配整个值的查询(本系列很早验证过text类型会先被分词器处理,term查询在text字段上经常匹配不到预期结果)在这里真实生效了。_reindex真实是ES里修正Mapping设计失误的唯一正规途径——不管是想改字段类型、调整分词器、还是重新规划分片数,只要涉及到已经固定下来的索引级结构,真实的操作模式永远是"建一个配置正确的新索引,把旧数据reindex过去,最后把应用层的alias指向新索引",而不是尝试在原地做手术。

分步演示:Reindex真实解决Mapping设计失误的唯一正规途径

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

从原地改类型被拒绝到reindex搬迁再到refresh才真正可见
这一步新验证的状态

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 _reindex API 与字段类型不可变性限制
    京ICP备2026067502号-1京公网安备11010502063487号