假设我们有一个巨大的MongoDB集合(大约60,000,000条记录),我们想滚动它而不获取大量的内存。对于Hibernate或m,这是可能的,因为有滚动的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 万(setFirstResult(4000000).setMaxResult(50000))开始找到下一批 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的选项是什么,可以获取会话中的对象并有效地索引它们?我的意思是,即使对于想要在没有休眠搜索的情况下使用 OGM 对大量数据进行分页的应用程序来说,这也是不可行的,所以我想有一个我没有看到的解决方案。
多谢。
Hibernate OGM 5.3.1,Hibernate Search 5.9.0 使用 ElasticSearch
OGM 尚不支持滚动,因为它需要不支持的条件 API。
话虽如此,您可以以不同的方式实现您的流程。
我将假设越来越慢的过程来自查询部分(MongoDB越来越难找到第N个结果),而不是来自索引部分(Elasticsearch越来越难将文档添加到索引中)。
如果是这种情况,您可以尝试"分块"查询而不是分页。这个想法是首先检索要编制索引的实体类型的第一个和最后一个 ID,然后不使用分页,而是使用类似于where ID between <last ID in the previous query + 1> AND <last ID in the previous query + page size>
的条件运行查询。
如果 ID 字段在 MongoDB 中具有升序索引,这应该会随着时间的推移而摆脱性能变差的情况。
您需要收集一些指标来了解它变慢的原因,只有这样我们才能提出有效的解决方案。
气相色谱
第一个疑点是你的 JVM 内存不足;我怀疑MongoDB/Java驱动程序可能会保留一些数据,可能比我们预期的要多。您能否在 JVM 上启用 GC 日志记录以验证其行为方式,或者附加任何分析器以查看整个过程中的内存使用量是否保持在合理水平内。
索引大小
任何Lucene或Elasticsearch索引在写入过程中都会变慢一些,同时它正在增长。这种减速应该不是很显着,所以我不认为这是你观察到的,但为了确保索引过程本身不会妨碍你可以尝试使用黑洞后端运行相同的进程。
hibernate.search.default.worker.backend blackhole
注意:此属性要求不使用 Elasticsearch indexmanager,因此您必须暂时将 Hibernate Search 配置切换到默认的 Lucene 索引模式。
从MongoDB加载
这是最有可能的问题,我将听从Yoann对此的出色建议,只需先检查前两点以确保这确实是问题所在。
作为替代解决方案,除了前面提到的解决方案之外,您还可以扩展MongoDBDialect并覆盖方法forEachTuple
。
这是检索要索引的数据的那个,所以如果你事先知道如何过滤你需要的数据,它可能是一个解决方案。
然后,您可以使用新的方言设置属性:hibernate.ogm.datastore.grid_dialect
方法: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
目前,此方法收集集合中的所有数据,因此仅当您未将质量索引器用于其他目的时,此方法才有效。