Elasticsearch重建索引reindex

Elasticsearch重建索引reindex教程

Elasticsearch 中一个 field 的设置是不能被修改的,如果要修改一个 Field,那么应该重新按照新的 mapping,建立一个 index,然后将数据批量查询出来,重新用 bulk api 写入 index 中。

批量查询的时候,建议采用 scroll api,并且采用多线程并发的方式来 reindex 数据,每次 scroll 就查询指定日期的一段数据,交给一个线程即可。

Elasticsearch重建索引reindex详解

一开始,依靠 dynamic mapping,插入数据,但是不小心有些数据是 2017-01-01 这种日期格式的,所以 title 这种 field 被自动映射为了 date 类型,实际上它应该是 string 类型的,如下:

PUT /my_index/my_type/3 { "title": "2017-01-03" }

运行后,如下:

{ "my_index": { "mappings": { "my_type": { "properties": { "title": { "type": "date" } } } } } }

当后期向索引中加入 string 类型的 title 值的时候,就会报错,如下代码:

PUT /my_index/my_type/4 { "title": "my first article" }

运行后,错误如下:

{ "error": { "root_cause": [ { "type": "mapper_parsing_exception", "reason": "failed to parse [title]" } ], "type": "mapper_parsing_exception", "reason": "failed to parse [title]", "caused_by": { "type": "illegal_argument_exception", "reason": "Invalid format: \"my first article\"" } }, "status": 400 }

如果此时想修改title的类型,是不可能的,代码如下:

PUT /my_index/_mapping/my_type { "properties": { "title": { "type": "text" } } }

错误如下:

{ "error": { "root_cause": [ { "type": "illegal_argument_exception", "reason": "mapper [title] of different type, current_type [date], merged_type [text]" } ], "type": "illegal_argument_exception", "reason": "mapper [title] of different type, current_type [date], merged_type [text]" }, "status": 400 }

此时,唯一的办法,就是进行 reindex,也就是说,重新建立一个索引,将旧索引的数据查询出来,再导入新索引。

如果说旧索引的名字,是 old_index,新索引的名字是 new_index,终端 java 应用,已经在使用 old_index 在操作了,难道还要去停止 java 应用,修改使用的 index 为 new_index,才重新启动 java 应用吗?这个过程中,就会导致 java 应用停机,可用性降低。

所以说,给 java 应用一个别名,这个别名是指向旧索引的,java 应用先用着,java 应用先用 goods_index alias 来操作,此时实际指向的是旧的 my_index:

PUT /my_index/_alias/goods_index

新建一个 index,调整其 title 的类型为 string:

PUT /my_index_new { "mappings": { "my_type": { "properties": { "title": { "type": "text" } } } } }

使用 scroll api 将数据批量查询出来:

GET /my_index/_search?scroll=1m { "query": { "match_all": {} }, "sort": ["_doc"], "size": 1 }

采用 bulk api 将 scoll 查出来的一批数据,批量写入新索引:

POST /_bulk { "index": { "_index": "my_index_new", "_type": "my_type", "_id": "2" }} { "title": "2017-01-02" }

反复循环,查询一批又一批的数据出来,采取 bulk api 将每一批数据批量写入新索引,将 goods_index alias 切换到 my_index_new 上去,java 应用会直接通过 index 别名使用新的索引中的数据,java 应用程序不需要停机,零提交,高可用:

POST /_aliases { "actions": [ { "remove": { "index": "my_index", "alias": "goods_index" }}, { "add": { "index": "my_index_new", "alias": "goods_index" }} ] }

直接通过 goods_index 别名来查询,是否 ok:

GET /goods_index/my_type/_search

基于 alias 对 client 透明切换 index:

PUT /my_index_v1/_alias/my_index

client 对 my_index 进行操作,reindex 操作,完成之后,切换 v1 到 v2:

POST /_aliases { "actions": [ { "remove": { "index": "my_index_v1", "alias": "my_index" }}, { "add": { "index": "my_index_v2", "alias": "my_index" }} ] }

Elasticsearch重建索引总结

Elasticsearch 中一个 field 的设置是不能被修改的,如果要修改一个 Field,那么应该重新按照新的 mapping,建立一个 index,然后将数据批量查询出来,重新用 bulk api 写入 index 中。