其实方案有三种:
- 外部数据导入方案
- 基于scroll+bulk+索引别名
- Reindex API 方案
第一种方案对数据库的压力和ES服务器压力都大,所以不做介绍
基于scroll+bulk+索引别名
- 若Java客户端没有使用别名,需要给客户端分配一个: PUT /book/_alias/book_alias
- 新建索引book_new,将mapping信息,settings信息等按新的要求全部定义好。
- 使用scroll api将数据批量查询出来
为了使用 scroll,初始搜索请求应该在查询中指定 scroll 参数,这可以告诉 Elasticsearch 需要 保持搜索的上下文环境多久,1m 就是一分钟。
GET /book/_search?scroll=1m
{
"query": {
"match_all": {}
},
"sort": [
"_doc"
],
"size": 2
}
采用bulk api将scoll查出来的一批数据,批量写入新索引
POST /_bulk
{ "index":
{
"_index": "book_new", "_id": "对应的id值"
}
}
{ 查询出来的数据值 }
反复执行修改后的步骤3和步骤4,查询一批导入一批,以后可以借助Java Client或其他语言的API支持。
GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "步骤三中查询出来的值"
}
切换别名book_alias到新的索引book_new上面,此时Java客户端仍然使用别名访问,也不需要修改任何代码,不需要停机。
POST /_aliases
{
"actions": [
{
"remove": {
"index": "book",
"alias": "book_alias"
}
},
{
"add": {
"index": "book_new",
"alias": "book_alias"
}
}
]
}
验证别名查询的是否为新索引的数据
Reindex API 方案
基础命令
POST _reindex
{
"source": {
"index": "book"
},
"dest": {
"index": "book_new"
}
}
如果不手动创建新索引book_new的mapping信息,那么Elasticsearch将启动自动映射模板对数据进行类型映射,可能不是期望的类型,这点要注意一下。
version_type
使用reindex api也是创建快照后再执行迁移的,这样目标索引的数据可能会与原索引有差异, version_type属性可以决定乐观锁并发处理的规则。
POST _reindex
{
"source": {
"index": "book"
},
"dest": {
"index": "book_new",
"version_type": "internal"
}
}
version_type属性含义如下:
- internal:直接拷贝文档到目标索引,对相同的type、文档ID直接进行覆盖,默认值
- external:迁移文档到目标索引时,保留version信息,对目标索引中不存在的文档进行创建,已存在的文档按version进行更新,遵循乐观锁机制。
op_type 属性和conflflicts 属性
如果op_type设置为create,那么迁移时只在目标索引中创建ID不存在的文档,已存在的文档,会提示 错误,如下请求:
如果加上”conflflicts”: “proceed”配置项,那么冲突信息将不展示,只展示冲突的文档数量POST _reindex
{
"source": {
"index": "book"
},
"dest": {
"index": "book_new",
"op_type": "create"
}
}
POST _reindex
{
"conflicts": "proceed",
"source": {
"index": "book"
},
"dest": {
"index": "book_new",
"op_type": "create"
}
}
query支持
POST _reindex
{
"size": 100,
"source": {
"index": "book",
"query": {
"term": {
"language": "english"
}
},
"sort": {
"likes": "desc"
}
},
"dest": {
"index": "book_new"
}
}