如何在一个非常大的ElasticSearch索引上改变映射类型?



我想将ElasticSearch映射属性从text更改为ip,但它们是不兼容的类型。

我知道公认的答案是:

  • 创建一个具有正确映射的新索引;
  • 运行_reindexAPI复制数据;
  • 煮一杯咖啡;
  • 删除原索引;
  • 创建一个从原索引到新索引的别名。

然而,我正在处理一个363GB索引中的5亿条记录,每天可能有数十万条新记录写入其中。上述过程在删除旧索引和创建新别名的过程中至少会有一些停机时间,并且在重新索引完成和下一步之间的时间内会有记录丢失。(重新驯鹿的过程需要几个小时,如果不是几天的话。)就地进行转换会更好,比如创建一个新字段并复制旧索引。什么好主意吗?

实际要简单得多。步骤如下:

。修改映射,将ip子字段添加到现有字段中,例如

PUT index/_mapping
{
"properties": {
"your_ip_field": {
"type": "text",
"fields": {
"ip": {
"type": "ip"
}
}
}
}
}

B。在索引

上调用index/_update_by_query?wait_for_completion=false&slices=auto

C。这里什么也没有,就是这样。

_update_by_query的调用将简单地获取每个_source文档并对其重新索引(即新版本),然后ip子字段将可用于您的查询。

每天写入索引的所有新文档将已经使用新的映射,旧的文档将在更新调用期间更新。不需要切换别名,也不需要重新索引。

当更新完成后,您将能够引用your_ip_field.ip字段字段来使用它的ip版本。

这样做的缺点是,您仍然将your_ip_field作为您可能不需要的倒排索引中的标记文本,但您不能全部拥有。还有更复杂的解决方案,但这个很简单,可以让你开始。

确实,重新索引这么大的索引不是一个好主意,我建议创建一个新字段,并使用摄取管道将其映射到新字段,并在应用程序端进行更改以获得正确的数据类型。(可以使用update_byQuery添加新字段)

另一个选项是使用运行时字段(在ES 7.11中引入),在这种情况下,您的解析将从索引时间切换到查询时间。

关于重新索引,您可以通过使用读写别名在ES中实现零停机重新索引,更多信息请查看这里。

感谢@Kaveh,我使用了摄取管道/update_by_query解决方案。

我将把这个解决方案描述为任何正在寻找它的人的答案。

0。我正在转换一个名为"user_ip"到名为"ip_addr"的IP字段;在"my_index">

你可以通过Kibana完成大部分工作,但我将使用ElasticSearch开发工具控制台风格,所以如果你喜欢,你可以在那里运行它。

1。创建摄取管道

按照这些说明,使用Kibana很容易做到这一点。摄取管道被命名为ip_transform。如果要将其作为代码运行,则如下所示:

PUT _ingest/pipeline/ip_transform
{
"processors": [
{
"convert": {
"field": "user_ip",
"type": "ip",
"target_field": "ip_addr",
"ignore_missing": true
}
}
]
}

2。在索引中创建字段

PUT my_index/_mapping
{
"properties": {
"ip_addr": {
"type": "ip"
}
}
}

3。将此设置为该索引的默认管道

这不是必须的,你可以在调用中添加?pipeline=ip_transform,但是我不想改变我的代码,我总是想运行这个管道。

PUT my_index/_settings
{
"index.default_pipeline": "ip_transform"
}

4。在现有记录上运行管道

我们使用_update_by_query API对每个现有记录运行管道。

POST my_index/_update_by_query?pipeline=ip_transform&wait_for_completion=false
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "ip_addr"
}
}
}
}
}

对于大数据集,这将花费一段时间,但是您可以获取返回的ID并查询它是否完整:

GET _tasks/<Job ID>

最新更新