微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

HibernateSearch:将单个表中的 5000 万行重新索引到 Elastic Search

如何解决HibernateSearch:将单个表中的 5000 万行重新索引到 Elastic Search

我们目前使用具有 7 个线程的 Mass Indexer认设置(每个查询加载 10 个对象)将 1 个表(8-10 个字段)中的数据重新索引到弹性搜索中。该表的大小目前为 25 million,并将增长到数亿。

MassIndexer indexer = searchSession.massIndexer(Entity.class)
            .threadsToLoadobjects(7);

indexer.start()
     .thenRun(() ->
         log.info("Mass Indexing Entity Complete")
     )
     .exceptionally(throwable -> {
         log.error("Mass Indexing Entity Failed",throwable);
         return null;
     });

数据库Postgres on RDS,我们使用的是 AWS Elastic SearchHibernate Search 版本是 6。

最近我们在重新索引过程中遇到了瓶颈,因为它在表中有 2000 万行的情况下运行了几个小时。原因之一是我们有一个最大连接数为 10 的连接池。使用当前的质量索引器设置(7 个线程),它只留下 2 个连接(1 个用于 Id 查找 + 7 个用于实体查找)用于导致等待连接超时的其他操作。我们将池大小增加到 20 并进行测试。

重新索引非常大的数据集的最佳策略是什么? MassIndexer 能否通过一些配置设置扩展到如此高的容量?或者我们应该看看其他策略吗?过去对具有相同要求的人有什么作用?

UPDATE:IDLoader 线程看起来也没有批处理,所以对于 5000 万行,它将在 1 个查询中加载内存中的所有 5000 万个 ID?

还有,idFetchSize 有什么用?貌似索引过程中没有用到。

解决方法

重新索引非常大的数据集的最佳策略是什么? MassIndexer 能否通过一些配置设置扩展到如此高的容量?

有这么多实体,事情肯定需要几分钟的时间。

它是否可以扩展...问题是,质量索引器只是您的数据库和 Elasticsearch 之间的中间人。假设您的数据库可以扩展,并且 Elasticsearch 可以扩展,那么大规模索引器扩展所需的唯一事情就是并行执行更多工作。你可以控制它。

现在,您的意思可能是“它能否在令人满意的时间内重新编制索引”,这当然取决于您的期望,以及您为调整它付出了多少努力。

海量索引的性能当然会受到您传递给海量索引器的配置的影响,但也会受到实体的架构和数据、您的 RDBMS 及其配置、您的 Elasticsearch 集群及其配置、机器的影响他们继续,......真的,没有人知道什么是可能的:唯一知道的方法就是尝试、评估结果、调整和迭代。

我建议首先专注于解决延迟加载问题,因为这些问题会对性能产生巨大影响;请务必设置 hibernate.default_batch_fetch_size 以减少延迟加载对性能的影响。

那么,我只能重复what the reference documentation says

MassIndexer 旨在尽快完成重新索引任务,但没有一刀切的解决方案,因此需要进行一些配置才能充分利用它。 性能优化可能会变得非常复杂,因此在尝试配置 MassIndexer 时请记住以下几点:

  • 始终测试您的更改以评估其实际效果:本节中提供的建议通常是正确的,但每个应用程序和环境都不同,某些选项在组合时可能会产生意想不到的结果。
  • 采取小步骤:在使用 40 个已索引实体类型(每个类型为 200 万个实例)调整大规模索引之前,尝试仅使用一种实体类型的更合理方案,可选择限制要索引的实体数量以更快地评估性能。
  • 在尝试调整并行索引多个实体类型的批量索引操作之前,请分别调整您的实体类型。

除了调整海量索引器之外,请记住它仅从数据库加载数据以将其推送到 Elasticsearch。可以肯定的是,质量索引器可能是瓶颈,但数据库或 Elasticsearch 也可能是瓶颈,如果它们的维度不足。确保两者都能提供令人满意的吞吐量:体面的机器,必要时集群,服务器端配置,......

不管怎样,你可以做很多事情:在做之前,试着找出瓶颈是什么。您的数据库是否始终处于 100% CPU?然后调整您的数据库:更改设置,使用更强大的机器,... Elasticsearch I/O 是否明显达到了极限?然后调整 Elasticsearch:更改设置,添加更多节点,...... Postgresql 和 Elasticsearch 都做得很好吗?那么也许你应该有更多的 DB 连接,或者更多的 ES 连接,或者你的质量索引器中的更多线程。或者也许是别的东西;表现很难。


或者我们应该看看其他策略吗?

我会把它作为最后的手段。如果您不了解质量索引器的性能究竟出了什么问题,那么您就不可能找到更好的解决方案。

如果您不相信 MassIndexer 能很好地完成工作,您可以尝试自己动手。设置一个加载 ID 的线程,以及其他加载相应实体的线程,然后 index them manually。要做到这一点并不容易,但这是可能的。

如果你这样做,我怀疑你会改进什么。但是,假设实体加载是瓶颈,而不是索引(您必须先检查!),我想您可以通过利用数据库的细节来获得更好的吞吐量:

  • 如果延迟加载似乎是问题所在,您可以使用 entity graphs 来确保已编入索引的实体的所有部分都将被急切加载。 MassIndexer 目前无法做到这一点,但希望有朝一日 (HSEARCH-521) 能够做到。
  • 如果在您的情况下有一些 JDBC 查询提示可以提高性能,您可以尝试设置它们。
  • 如果它不仅能够处理负载,而且瓶颈似乎是将实体处理为文档,那么您可以尝试对 ID 进行分区并在多台机器上运行您的“自定义索引过程”。例如。在一台机器上重新索引 ID 1 到 25,000,000,在另一台机器上重新索引 ID 25,001 到 50,000。您不能使用 mass indexer 来做到这一点,因为它不允许过滤 ID(至少在 Hibernate Search 6.0 中不允许,但在 6.1 中允许:HSEARCH-499

更新:IDLoader 线程似乎没有批处理,因此对于 5000 万行,它将在 1 个查询中加载内存中的所有 5000 万个 ID?

不,ID 是批量加载的。然后将每个批次推送到内部队列,并由加载线程使用。批次大小由 batchSizeToLoadObjects 控制。

一个例外是 MySQL,它的默认配置是将整个结果集加载到内存中(不要问我为什么),但这并不影响 PostgreSQL。无论如何,这可以解决(见下文)。

有关参数 here 的更多信息。


还有,idFetchSize 有什么用?貌似索引过程中没有用到。

这是 JDBC 提取大小。使用滚动(游标)检索 ID,JDBC 提取大小是 JDBC 驱动程序中此滚动的结果页(~低级缓冲区)的大小。

老实说,它对 MySQL(也许还有 MariaDB?)最有用,即使我们使用游标,其 JDBC 驱动程序也会将所有结果加载到内存中,除非提取大小设置为 Integer#MIN_VALUE。我知道,这很奇怪。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?