有没有更聪明的方法重新索引elasticsearch?

46

我这样问是因为我们的搜索功能处于流动状态,正在解决问题。但是每次我们更改索引(更改分词器或过滤器,或分片/副本数量),我们都必须删除整个索引并重新将所有Rails模型重新索引到Elasticsearch中……这意味着我们必须考虑停机时间来重新索引所有记录。

我不知道是否有更聪明的方法可以做到这一点?

4个回答

73

我认为@karmi说得对,但让我用更简单的方式解释一下。我需要偶尔通过添加一些新属性或分析设置来升级生产架构。

最近,我开始使用下面描述的场景进行实时、持续负载、零停机索引迁移。您可以远程执行此操作。

以下是步骤:

假设:

  • 您有索引real1和别名real_writereal_read指向它,
  • 客户端仅写入real_write并仅从real_read读取,
  • _source文档属性可用。

1. 新索引

创建带有新映射和您选择的设置的real2索引。

2. 写入别名切换

使用以下批量查询切换写别名。

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_write" } },
        { "add" : { "index" : "real2", "alias" : "real_write" } }
    ]
}'

这是原子操作。从此时起,real2 将在所有节点上填充新客户端数据。阅读器仍通过 real_read 使用旧的 real1。这是最终一致性。

3. 旧数据迁移

必须将数据从 real1 迁移到 real2,但不能用旧条目覆盖 real2 中的新文档。迁移脚本应使用 bulk API 和 create 操作(而非 indexupdate)。我使用简单的 Ruby 脚本 es-reindex,它具有良好的预计完成时间状态:

$ ruby es-reindex.rb http://esserver:9200/real1 http://esserver:9200/real2

更新于2017年您可以考虑使用新的重新索引API,而不是使用脚本。它有很多有趣的功能,比如冲突报告等。

4. 读取别名切换

现在real2已经更新并且客户端正在向其写入数据,但他们仍然从real1中读取数据。让我们更新读取别名:

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_read" } },
        { "add" : { "index" : "real2", "alias" : "real_read" } }
    ]
}'

5. 备份并删除旧索引

写入和读取操作使用real2。您可以备份并从ES集群中删除real1索引。

完成!


谢谢。es-reindex脚本只是从现有索引中复制,如果需要从数据库更新数据,则应在此处使用河流导入,对吗? - Kevin
实际上我还没有使用River。我只会根据我的需求更改es-reindex脚本,例如更新有效载荷。请记住,如果您引入冲突的更改,则实时迁移可能不可行。 - gertas
脚本似乎也复制了映射。它会覆盖步骤1中创建的映射吗? - cmonkey
@cmonkey 不,映射仅在不存在时创建(es-reindex.rb:90),或者当使用“-r”选项首先删除它时。 - gertas
2
我们已经将那个有用的脚本扩展成了一个完整的宝石(gem):https://github.com/mojolingo/es-reindex - Justin Aiken
1
这并没有解决某些应用程序的要求,即写入后跟随搜索显示更新的写入。您必须同时写入两个索引。您可以有两个写入别名(ES不允许一个别名扇出到两个索引)。但是,当您决定删除第二个别名时,您的应用程序或后台DB-> ES数据推送器和重新索引过程之间会发生竞争。任何写入都将出现错误。您的应用程序也不知道何时应开始多个写入。 - Paul S

30

是的,有更聪明的方法可以在不停机的情况下重新索引您的数据。

首先,永远不要使用“最终”索引名称作为真实的索引名称。因此,如果您想将索引命名为“文章”,请不要使用该名称作为物理索引,而是创建一个索引,例如“articles-2012-12-12”或“articles-A”、“articles-1”等。

其次,创建一个名为“alias”的别名指向该索引。然后,您的应用程序将使用这个别名,因此您永远不需要手动更改索引名称、重新启动应用程序等。

第三,在您想要或需要重新索引数据时,将它们重新索引到一个不同的索引中,比如说“articles-B”——Tire的索引工具链中的所有工具都支持您在这里。

完成后,将别名指向新索引。通过这种方式,您不仅可以最小化停机时间(没有任何停机时间),还可以获得一个安全的快照:如果您在新索引中进行索引时出现了问题,您可以切换回旧索引,直到解决问题为止。


我的问题是我将所有的模型都索引到了一个索引中,我想知道,在这种情况下是否有一种方法可以将重新索引到不同的索引中?当我在Rails模型中指定index_name为“articles”时,“rake environment tire:import CLASS='Article' INDEX='articles-2011-05'”实际上会索引到“articles-2011-05”吗? - concept47
3
@karmi..我这里有一个疑问。您说在将数据迁移到新索引后,将别名指向新索引。但是,在数据迁移过程中,如果没有停机时间,新的数据将插入到旧索引中,而新索引将没有这些新数据。我们如何避免数据丢失? - rubyprince
@rubyprince 这是一个合理的疑虑。你要么在迁移期间禁用/缓冲更新,要么在新索引上重放更新。 - karmi
2
这里有一篇很好的文章描述了如何在零停机时间下更改映射:http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/ - Adrian Carr
1
@karmi...我关注rubyprince指出的数据丢失问题,除了重新索引旧索引插入的新数据之外,我们有更好的方法吗? - user2756589
我们在大规模上进行这项工作,这已经被证明对我们非常有效。 - Kenny Cason

3

我最近写了一篇博客文章,介绍了如何在没有停机的情况下进行重新索引。需要花费一些时间来确定需要做好的各种小事情。希望这能对你有所帮助!

https://summera.github.io/infrastructure/2016/07/04/reindexing-elasticsearch.html

总结:

步骤1:准备新索引

使用新映射创建新索引。这可以在Elasticsearch的同一实例上或全新实例上完成。

步骤2:保持索引最新

在重新索引期间,您需要让新旧两个索引保持最新状态。对于写操作,可以将写操作发送到新旧两个索引的后台工作程序中。

删除操作有些棘手,因为在删除记录并重新索引到新索引之间存在竞争条件。因此,在重新索引期间,您需要跟踪需要删除的记录,并在完成后处理这些记录。如果您没有执行太多删除操作,则另一种方法是在重新索引期间消除删除的可能性。

步骤3:执行重新索引

您需要使用滚动搜索来读取数据,使用批量API进行插入。由于在第二步之后,您将在后台将新的和更新的文档写入新索引,因此您要确保不使用批量API请求更新新索引中的现有文档。
这意味着您想要的批量API请求操作是创建,而不是索引。根据文档:“如果已经存在具有相同索引和类型的文档,则创建将失败,而索引将根据需要添加或替换文档”。这里的主要问题是您不希望滚动搜索快照中的旧数据覆盖新索引中的新数据。
在github上有一个很棒的脚本可以帮助您完成此过程:es-reindex
第4步:切换。
一旦重新索引完成,就该将搜索切换到新索引。您需要打开删除或处理新索引的排队删除作业。您可能会注意到,在开始时搜索新索引有点慢。这是因为Elasticsearch和JVM需要时间来热身。
进行任何所需的代码更改,以便应用程序开始搜索新索引。如果遇到问题并需要回滚,则可以继续写入旧索引。如果您觉得这是不必要的,则可以停止写入旧索引。
步骤5:清理
此时,您应该已完全转换到新索引。如果一切顺利,请执行任何必要的清理,例如:
删除与新主机不同的旧索引主机 删除与旧索引相关的序列化代码

2
你真的应该将博客文章中的相关信息包含在答案中。如果你的博客文章因为某些原因需要消失,那么这个答案就变得毫无用处了。 - Chris Peters
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。- 来自审查 - Vasseurth
1
@Vasseurth,感谢您的推荐。我的回答已经更新,附有文章摘要。 - Ari

2
也许可以创建另一个索引,将所有数据重新索引到该索引上,然后在重新索引完成后进行切换?

嗯...在我们的情况下,我们有一个Rails应用程序,其中所有索引都是硬编码的,很难将其更改然后再改回来。我想知道是否可以启动一个新节点来重新索引,但是Elasticsearch会将分片重新分配到您创建的新节点中:\ - concept47

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接