索引重建 - reindex

reindex 是 ES 提供的一个 api 接口,实现集群内部或跨集群跨索引同步数据。

使用场景

  1. 分片数变更:当数据量过大,而索引最初创建的分片数量不足,导致数据入库较慢的情况,此时需要扩大分片的数量,此时可以尝试使用Reindex。

  2. mapping字段变更:当数据的mapping需要修改,但是大量的数据已经导入到索引中了,重新导入数据到新的索引太耗时;但是在ES中,一个字段的mapping在定义并且导入数据之后是不能再修改的,所以这种情况下也可以考虑尝试使用Reindex。

  3. 分词规则修改,比如使用了新的分词器或者对分词器自定义词库进行了扩展,而之前保存的数据都是按照旧的分词规则保存的,这时候必须进行索引重建。


ES提供了_reindex API,相比于先把数据从index导出来再导入新的index速度会快很多,实测速度大概是bulk导入数据的5-10倍。reindex适合做跨索引、跨集群的数据迁移。

Reindex 不会尝试设置目标索引,它不会复制源索引的设置。在运行_reindex操作之前需要设置目标索引,包括设置映射、分片计数、副本等。

reindex测试

上一章我们创建了/reviews索引,它的Mapping定义如下:

GET /reviews/_mapping
{
  "reviews": {
    "mappings": {
      "properties": {
        "author": {
          "properties": {
            "email": {
              "type": "keyword"
            },
            "first_name": {
              "type": "text"
            },
            "last_name": {
              "type": "text"
            }
          }
        },
        "content": {
          "type": "text"
        },
        "create_at": {
          "type": "date"
        },
        "product_id": {
          "type": "integer"
        },
        "rating": {
          "type": "float"
        }
      }
    }
  }
}

现在假设业务的product_id需要使用字符串表示,需要将原来的integer类型更新为keyword类型。由于Elasticsearch不支持在已有索引上更新字段的属性,此时可以使用reindex,重新创建一个索引,并把原来的数据导入过去


创建新的索引/reviews_new,注意product_id此时更新为keyword类型:

PUT /reviews_new
{
  "mappings": {
      "properties": {
        "author": {
          "properties": {
            "email": {
              "type": "keyword"
            },
            "first_name": {
              "type": "text"
            },
            "last_name": {
              "type": "text"
            }
          }
        },
        "content": {
          "type": "text"
        },
        "create_at": {
          "type": "date"
        },
        "product_id": {
          "type": "keyword"
        },
        "rating": {
          "type": "float"
        }
      }
    }
}

然后执行_reindex API:

POST /_reindex
{
  "source": {
    "index": "reviews"
  },
  "dest": {
    "index": "reviews_new"
  }
}

执行后显示成功插入的数据条数及所用时间:

image-20220717220959399

_reindex背后也是先将源索引的文档取回,再插入到目标索引:

image-20220717000326300

执行查询确认新的索引中成功插入了数据:

image-20220717221056224

但是上面product_id中原始数据依然显示为整数格式,在reindex时可以使用script来将其转换成为字符串。

先将原来导入的数据删除掉:

POST /reviews_new/_delete_by_query
{
  "query":{
    "match_all":{}
  }
}

image-20220717221738347

重新reindex,这次使用script将整数转换成字符串:

POST /_reindex
{
  "source": {
    "index": "reviews"
  },
  "dest": {
    "index": "reviews_new"
  },
  "script": {
    "source": """
    if (ctx._source.product_id != null) {
      ctx._source.product_id = ctx._source.product_id.toString(); 
    }
    """
  }
}

image-20220717222015048

查看新的索引中的数据,product_id以字符串形式展现:

image-20220717222102878