什么时候需要重建索引

以下情况需要执行 reindex:

  • 索引的 mappings 发生变更
  • 索引的 settings 发生变更
  • 集群内或集群间需要做数据迁移

数据预处理

使用 Ingest Pipeline 预处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
PUT _ingest/pipeline/split_xxx
{
"processors": [
{
"split": {
"field": "xxx",
"separator": ","
},
{
"set": {
"field": "xxx",
"value": "0"
}
}
}
]
}

# reindex
POST _reindex
{
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new",
"pipeline": "split_xxx"
}
}

使用 Script 脚本处理数据

ES 支持的 Painless 脚本非常强大,以下是一个简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST _reindex
{
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new"
},
"script": {
"source": "ctx._source.age += 2",
"lang": "painless"
}
}

字段重命名

使用 Script 将 name 字段重命名为 newName

1
2
3
4
5
6
7
8
9
10
11
12
13
POST _reindex
{
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new"
},
"script": {
"source": "ctx._source.newName = ctx._source.remove(\"name\")",
"lang": "painless"
}
}

只同步部分字段

只将指定字段从源索引复制到目标索引:

1
2
3
4
5
6
7
8
9
10
POST _reindex
{
"source": {
"index": "index_old",
"_source": ["name", "age"]
},
"dest": {
"index": "index_new"
}
}

只创建目标索引中不存在的文档

1
2
3
4
5
6
7
8
9
10
POST _reindex
{
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new",
"op_type": "create"
}
}

设置批次大小

reindex 底层使用 scroll,默认每批 1000 条,可按需调大:

1
2
3
4
5
6
7
8
9
10
POST _reindex
{
"source": {
"index": "index_old",
"size": 5000
},
"dest": {
"index": "index_new"
}
}

遇到版本冲突时继续执行

1
2
3
4
5
6
7
8
9
10
11
POST _reindex
{
"conflicts": "proceed",
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new",
"op_type": "create"
}
}

只 reindex 符合条件的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST _reindex
{
"source": {
"index": "index_old",
"query": {
"term": {
"name.keyword": {
"value": "冬哥"
}
}
}
},
"dest": {
"index": "index_new"
}
}

排除不想同步的字段

1
2
3
4
5
6
7
8
9
10
11
12
POST _reindex
{
"source": {
"index": "index_old",
"_source": {
"excludes": ["name"]
}
},
"dest": {
"index": "index_new"
}
}

不停机 reindex(使用 alias)

Alias

一个索引可以接受多个别名,一个别名也可以映射到多个索引;别名可以关联 filter 并自动应用到检索。别名不能与索引同名。同一 API 请求中,移除和添加别名是原子操作,无需担心短暂的空窗期。

1
2
3
4
5
6
7
8
9
# 添加别名示例:
PUT /my_index_name/_alias/alias_name

POST /_aliases
{
"actions": [
{ "add": { "index": "my_index__name_v2", "alias": "alias_name" }}
]
}

步骤:首先确保旧索引有别名且业务方通过别名访问,然后新建索引并将旧索引数据 reindex 过去:

1
2
3
4
5
6
7
8
9
POST _reindex
{
"source": {
"index": "old_index"
},
"dest": {
"index": "new_index"
}
}

最后原子地将别名从旧索引切换到新索引:

1
2
3
4
5
6
7
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_name_v1", "alias": "alias_name" }},
{ "add": { "index": "my_index__name_v2", "alias": "alias_name" }}
]
}

停机 reindex(未建别名的情况)

操作步骤:

  1. 创建一个中间索引
  2. 将源索引数据(含 mapping)备份到中间索引
  3. 查询确认数据是否 copy 成功
  4. 删除有问题的源索引
  5. 重新创建同名索引(★ 字段类型修改正确 ★)
  6. 从中间索引还原数据到源索引
  7. 删除中间索引

建中间索引

可在 Kibana 索引管理页面直接复制 mapping。ES 7 之后不支持 type,记得去掉 mapping 下的 _doc 层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
PUT prod-sopei-reindex
{
"mappings": {
"dynamic_templates": [
{
"message_field": {
"path_match": "message",
"match_mapping_type": "string",
"mapping": {
"norms": false,
"type": "text"
}
}
},
{
"string_fields": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"norms": false,
"type": "text"
}
}
}
],
"properties": {
"@timestamp": {
"type": "date"
},
"@version": {
"type": "keyword"
}
...
}
}
}

将源索引数据 copy 到中间索引(异步)

wait_for_completion=false 表示异步执行。注意:Kibana 默认超时 30s,可修改 kibana.yml 中的 elasticsearch.requestTimeout(治标不治本)。

1
2
3
4
5
6
7
8
9
10
11
POST _reindex?wait_for_completion=false
{
"source": {
"index": "xxx-20210916"
},
"dest": {
"index": "xxx-reindex"
}
}
# 查询reindex任务进度
GET _tasks?detailed=true&actions=*reindex

查询确认数据是否 copy 成功

1
GET xxx-reindex/_search

删除旧索引

1
DELETE xxx-20210916

重新创建同名索引(★ Mapping 取自新索引 ★)

1
2
3
4
PUT xxx-20210916
{
...
}

还原数据到源索引

1
2
3
4
5
6
7
8
9
10
11
POST _reindex?wait_for_completion=false
{
"source": {
"index": "xxx-reindex"
},
"dest": {
"index": "xxx-20210916"
}
}
# 查询reindex任务进度
GET _tasks?detailed=true&actions=*reindex

删除中间索引

1
DELETE xxx-reindex