Hibernate OGM 分页滚动

Hibernate OGM pagination-scroll

让我们假设我们有一个巨大的 mongodb 集合(大约 60,000,000 条记录)并且我们想要滚动它而不需要获取大量内存。对于 Hibernate orm,有滚动 api 和标准查询是可能的,但是 OGM 中分页的解决方案是什么(已经花了很多时间但我找不到东西)?我正在使用 setFirstResult-setMaxResult Api 对 50,000 个对象进行批量索引。这些是从

等查询中获取批次的时间(以秒为单位)
em.createNativeQuery(query, Entity.class).setFirstResult(i).setMaxResults(batchSize).getResultList()
results.stream().forEach(res -> fullTextEntityManager.index(res));

通过在每次迭代中增加 i,例如 i+=batchSize;

我已经尝试过使用 OgmMassIndexer,但我需要能够开始-停止、索引​​特定范围,所以我更喜欢手动操作。

很明显,每次迭代中找到第一个结果的时间都在增加,这很明显且合乎逻辑。 在这里我有时间以秒为单位从 400 万开始找到下一批 50000(setFirstResult(4000000).setMaxResult(50000)):

例如。去 4000000 花了 17 秒等。 去 4050000 花了 15 秒等等。 去 4100000 花了 12 秒等。 但后来这个数字增加了很多:

找到:17 找到:15 找到:12 找到:13 找到:13 找到:13 找到:15 找到:16 找到:16 找到:17 找到:18 找到:18 找到:19 找到:19 找到:20 找到:20 找到:21 找到:21 找到:22 找到:21 找到:22 找到:23 找到:23 找到:23 找到:24 找到:24 找到:25 找到:25 找到:26 找到:26 找到:27 找到:28 找到:27 找到:29 找到:29 找到:30 找到:31 找到:32 找到:33 找到:30 找到:33 找到:32 找到:34 找到:34 找到:35 找到:35 找到:38 找到:36 找到:38 找到:36 找到:41 找到:41 找到:39 找到:41 找到:41 找到:40 找到:42 找到:43 找到:42 找到:44 找到:44 找到:45 找到:47 找到:45 找到:44 找到:44 找到:47 找到:44 找到:47 找到:47 找到:50 找到:52 找到:93

是否有使用 ogm 游标或其他方式滚动 mongodb 的任何选项来获取会话中的对象并有效地为它们编制索引?我的意思是,即使对于想要在没有 Hibernate Search 的情况下使用 OGM 对大量数据进行分页的应用程序,这也是不可行的,所以我想有一个我没有看到的解决方案。

非常感谢。

Hibernate OGM 5.3.1,使用 ElasticSearch 的 Hibernate Search 5.9.0

OGM 尚不支持滚动,因为它需要不支持的条件 API。

话虽如此,您可以采用不同的方式实施您的过程。

我假设这个过程变得越来越慢来自查询部分(MongoDB 越来越难找到第 N 个结果)而不是来自索引部分(Elasticsearch 越来越难找到并且更难将文档添加到索引)。

如果是这种情况,您可以尝试 "chunk" 查询而不是分页。这个想法是首先检索要索引的实体类型的第一个和最后一个 ID,然后不使用分页,运行 查询条件类似于 where ID between <last ID in the previous query + 1> AND <last ID in the previous query + page size>.

如果 ID 字段在 MongoDB 中有升序索引,这应该可以避免性能随着时间的推移而变差。

您需要收集一些指标来了解速度变慢的原因,只有这样我们才能提出有效的解决方案。

GC

第一个怀疑是你的JVM运行内存不足;我怀疑 MongoDB/Java 驱动程序可能会保留某些数据,可能比我们预期的要多。您能否在 JVM 上启用 GC 日志记录以验证其行为方式,或者附加任何分析器以查看内存使用率在整个过程中是否保持在合理的水平内。

索引大小

任何 Lucene 或 Elasticsearch 索引在其增长过程中都会在写入过程中变慢一点。这种减速应该不会很明显,所以我不认为这是你所观察到的,但为了确保索引过程本身不在你可以尝试 运行 与 黑洞后端。

hibernate.search.default.worker.backend blackhole

N.B。 属性 要求不使用 Elasticsearch 索引管理器,因此您必须暂时将 Hibernate 搜索配置切换到默认的 Lucene 索引模式。

正在从 MongoDB

加载

这是最有可能的问题,我会听从 Yoann 对此的出色建议,只需先检查前两点以确保这确实是问题所在。

作为替代解决方案,除了前面提到的解决方案之外,您还可以扩展 MongoDBDialect 并覆盖方法 forEachTuple.

这是检索要编制索引的数据的方法,因此如果您事先知道如何过滤所需的数据,这可能是一种解决方案。

然后您可以使用您的新方言设置 属性: hibernate.ogm.datastore.grid_dialect

Foreach 方法:https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/main/java/org/hibernate/ogm/datastore/mongodb/MongoDBDialect.java#L848

当前供应商:https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/main/java/org/hibernate/ogm/datastore/mongodb/MongoDBDialect.java#L1924

目前此方法收集集合中的所有数据,因此只有当您没有在其他任何地方使用质量索引器用于不同目的时,此方法才有效。