使用Reindex修改索引字段的解决方案
需求前言
平时我们业务上,对于一个已建的索引,需要修改它的字段,或者新增字段是很平常的需求。
对于新增字段,无论是索引已建还是未建情况,ES提供dynamic Mapping的方式都可以解决:是根据添加文档时,ES帮我们根据文档的信息自动推算出了各个字段的信息。但是啊,推算的东西它不一定是准确的,很多时候并不是我们想要的东西!
所以我们一般是提前定义索引的mapping,而不是使用dynamic Mapping,避免在添加文档时让ES推断新增的字段类型!
但需求要在已有的索引上添加字段,最快的方案还是用dynamic mapping添加文档的方式让ES推断新加的字段;
但文本讨论的重点是对于已有索引,修改它字段属性的情况:就不能用dynamic Mapping的方式,直接修改会报错(包括也不能改变分片的数量,也会报错),只能通过新建索引的方式来修改,具体的方式是通过Reindex;
直接修改报错的情况
先创建test_index索引:
PUT test_index
{
"mappings": {
"properties": {
"test_id": {
"type": "keyword"
}
}
}
}
然后直接修改该索引:
PUT test_index/_mapping
{
"properties": {
"test_name": {
"type": "keyword"
}
}
}
因为在Mapping 中已经定义好的字段是不能修改的,所以报错信息如下:
{
"error" : {
"root_cause" : [
{
"type" : "illegal_argument_exception",
"reason" : "mapper [test_name] cannot be changed from type [keyword] to [text]"
}
]
},
"status" : 400
}
直接报400了
Reindex演示
# 删除索引,如果存在的话
DELETE test_index
# 创建索引
PUT test_index
{
"mappings": {
"properties": {
"test_id": { "type": "keyword" },
"test_name": { "type": "keyword" }
}
}
}
# 插入数据
PUT test_index/_doc/1
{
"test_id": "321",
"test_name": "hello,lvan"
}
# 创建新的索引,并且满足需求
PUT test_index_reindex
{
"mappings": {
"properties": {
"test_id": { "type": "keyword" },
"test_name": { "type": "text" }
}
}
}
# 执行 reindex 操作
POST _reindex
{
"source": { "index": "test_index" },
"dest": { "index": "test_index_reindex" }
}
如上,在执行Reindex的api,source为已有的test_index,dest为新创建且需求要改变属性的test_index_reindex;其实是将test_index索引的数据复制到另一个test_index_reindex索引中,起到迁移数据的作用;
对于Reindex的调优
①一般索引的数据量是非常大的,那如上例操作reindex api时,迁移所需时间就非常久,因为它是需要同步返回的,分分钟出现超时,可以使用wait_for_completion=false 参数,如下:
# 异步地执行 _reindex
POST _reindex?wait_for_completion=false
{
"source": { "index": "test_index" },
"dest": { "index": "test_index_reindex" }
}
# 结果
{
"task" : "26d0dAjcRYygigd0shfz5w:35995695"
}
它就启动一个线程异步执行,然后可以通过返回的task值,用get请求来查看是否迁移成功,如下:
GET /_tasks/26d0dAjcRYygigd0shfz5w:35995695
②Reindex的原理,是对旧索引的读,然后写入新索引,所以可以从读写方面入手优化,可以使用Sliced Scroll 来并行读取;然后写就可以调整Bulk Size的大小,避免它写的时候分多次写入;
如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!