我有一个项目,我刚刚转换为Spring Data JPA。该项目使用Hibernate Search,我需要一种方法来索引数据库中现有的(约1500万条)记录。
由于我正在处理如此大量的记录,因此无法使用Hibernate Search的MassIndexer,因为这会导致内存不足问题。
从我读过的内容(这里:http://docs.jboss.org/hibernate/search/4.2/reference/en-US/html/manual-index-changes.html#search-batchindex),建议的方法是这样的:
fullTextSession.setFlushMode(FlushMode.MANUAL);
fullTextSession.setCacheMode(CacheMode.IGNORE);
transaction = fullTextSession.beginTransaction();
//Scrollable results will avoid loading too many objects in memory
ScrollableResults results = fullTextSession.createCriteria( Email.class )
.setFetchSize(BATCH_SIZE)
.scroll( ScrollMode.FORWARD_ONLY );
int index = 0;
while( results.next() ) {
index++;
fullTextSession.index( results.get(0) ); //index each element
if (index % BATCH_SIZE == 0) {
fullTextSession.flushToIndexes(); //apply changes to indexes
fullTextSession.clear(); //free memory since the queue is processed
}
}
transaction.commit();
但是,我想注入我在Spring中配置的实体管理器。
我已经读过我可以通过在实体管理器上使用getDelegate()
方法来获取Hibernate会话,但是这会导致一个错误,指出一旦我尝试设置任何属性,Hibernate会话就会关闭在会议上:
public void reindexListings() throws InterruptedException {
Session session = (Session) em.getDelegate();
FullTextSession fts = Search.getFullTextSession(session);
try {
fts.setFlushMode(FlushMode.MANUAL);
} catch (Exception e) {
// Throws stack trace here stating that the Hibernate session is closed.
e.printStackTrace();
}
fts.setCacheMode(CacheMode.IGNORE);
Transaction transaction = fts.beginTransaction();
// Scrollable results will avoid loading too many objects in memory
ScrollableResults results = fts.createCriteria(EListing.class)
.setFetchSize(25).scroll(ScrollMode.FORWARD_ONLY);
int index = 0;
while (results.next()) {
index++;
fts.index(results.get(0)); // index each element
if ((index % 25) == 0) {
fts.flushToIndexes(); // apply changes to indexes
fts.clear(); // free memory since the queue is processed
}
}
transaction.commit();
}
我还读过我可以使用HibernateUtil
来获取会话(http://www.17od.com/2006/11/06/using-managed-sessions-in-hibernate-to-ease-unit-testing/),但同样,这并没有使用我的实体管理器。
不确定我到目前为止是否走上了正确的道路,或者我是否需要以完全不同的方式做到这一点,但到目前为止我发现的任何内容似乎都无法发挥作用。
答案 0 :(得分:2)
MassIndexer专为大量数据而设计,不应导致内存不足问题。
如果你正在使用MySQL,你是否注意到引用上的警告:
MassIndexer使用仅向前滚动的结果来迭代 要加载的主键,但MySQL的JDBC驱动程序将加载所有 记忆中的价值;避免这种“优化”设置idFetchSize Integer.MIN_VALUE的。
如果这不是问题,请尝试将MassIndexer选项设置为不太激进的值:
fullTextSession.createIndexer()
.threadsForSubsequentFetching( X )
.threadsToLoadObjects( Y )
.batchSizeToLoadObjects( Z )
.progressMonitor( progressMonitor )
.startAndWait();
或者只是将堆大小调整为更大的值:重新索引所有这些东西需要花费时间,所以如果你能给它更多的内存它会更有效率。
使用 MassIndexer.limitIndexedObjectsTo(long)来试验不同的值,但请记住,至少需要15分钟来平衡性能。