Hibernate OGM分页滚动

时间:2018-04-12 15:01:11

标签: java mongodb hibernate hibernate-search hibernate-ogm

让我们假设我们有一个庞大的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));

通过使用like i + = batchSize;

在每次迭代中增加i

我已经尝试过使用OgmMassIndexer,但我需要能够启动 - 停止,索引特定的范围,所以我更喜欢手动执行。

因为在每次迭代中找到firstResult的时间越来越明显且合乎逻辑。 在这里,我有时间在秒内从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,Hibernate Search 5.9.0使用ElasticSearch

3 个答案:

答案 0 :(得分:3)

OGM尚不支持滚动,因为它需要不支持Criteria API。

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

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

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

如果ID字段在MongoDB中有一个升序索引,那么随着时间的推移,这应该会降低性能。

答案 1 :(得分:1)

您需要收集一些指标以了解其减速的原因,然后我们才能建议有效的解决方案。

<强> GC

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

索引大小

任何Lucene或Elasticsearch索引在写入期间会逐渐减慢。这种放慢速度不应该非常显着,所以我认为这不是你所观察到的,而是要确保索引过程本身不是你可以尝试使用 blackhole运行相同的过程后端。

hibernate.search.default.worker.backend blackhole

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

从MongoDB加载

这是最有可能出现的问题,我会按照Yoann的优秀建议,只需先检查前两点,确保这实际上是问题。

答案 2 :(得分:1)

作为替代解决方案,除了前面提到的解决方案之外,您还可以扩展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

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