我有一个包含大约40列和7个集合的实体。集合不是延迟加载的。使用Hibernate Search MassIndexer索引500 000个实体大约需要2-3个小时。我使用下面的代码:
fullTextSession.createIndexer()
.batchSizeToLoadObjects(1000)
.threadsToLoadObjects(8).start();
我甚至尝试使用延迟加载来查看差异,然后需要大约1小时,这并不像我希望的那么快。
如果有一个实体只包含我要索引的列,包含ID列的3列,那么为了尝试性能会是什么样的,我创建了一个只包含这三列的实体。索引现在非常迅速,只用了3分钟。
使用不同实体的方法不是我想要的,因为每次更新原始实体时需要手动更新索引(据我所知,它是如何工作的)。然后我考虑使用flushToIndexes()方法和投影,而不是MassIndexer。
我根据https://docs.jboss.org/hibernate/search/4.4/reference/en-US/html_single/#search-batchindex-flushtoindexes编写了以下代码,并添加了投影部分。
Session session = sessionFactory.openSession();
try {
int batchSize = 1000;
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.setFlushMode(FlushMode.MANUAL);
fullTextSession.setCacheMode(CacheMode.IGNORE);
Transaction transaction = fullTextSession.beginTransaction();
//Scrollable results will avoid loading too many objects in memory
ScrollableResults results = fullTextSession.createCriteria( Report.class )
.setProjection(Projections.projectionList()
.add(Projections.property("reportId"), "reportId")
.add(Projections.property("header"), "header")
.add(Projections.property("description"), "description")
)
.setResultTransformer(Transformers.aliasToBean(Report.class))
.setFetchSize(batchSize)
.scroll( ScrollMode.FORWARD_ONLY );
int index = 0;
while( results.next() ) {
index++;
fullTextSession.index( results.get(0) ); //index each element
if (index % batchSize == 0) {
fullTextSession.flushToIndexes(); //apply changes to indexes
fullTextSession.clear(); //free memory since the queue is processed
}
}
transaction.commit();
} catch (Exception e) {
log.error(e);
} finally {
session.close();
}
运行代码时,我在代码(fullTextSession.index(results.get(0));
)中尝试索引第一个元素时会出现异常:
org.hibernate.TransientObjectException:该实例未与此会话相关联
我不明白为什么会遇到这个例外。我已经读过如果使用不同的Hibernate会话会发生这种情况,但在这种情况下,我在一个Hibernate会话中完成所有工作。
有没有其他人尝试将投影与Hibernate Search索引一起使用?应该可以使用吗?有关该主题的任何信息都表示赞赏。
一些版本信息:我使用的是Hibernate 4.2.17.Final和Hibernate Search 4.4.6.Final。由于依赖性,我无法使用最新版本。
答案 0 :(得分:0)
使用投影(当前)不是一个选项,因为投影结果与对象无关:它是瞬态的。 FullTextSession #index()方法需要一个托管对象,因此您将获得 TransientObjectException 。
在设计 MassIndexer 时,我考虑过使用预测,但它似乎并没有给我带来显着的好处;有趣的是,你报告这在你的情况下是有用的。你确定你所有的关系都是懒惰的吗?你确定索引过程不需要那些懒惰的关系吗?
如果您只是通过加载一些较少的数据列来确认您看到了如此显着的性能优势,那么我们可以考虑修补它。理想情况下,我们可以使这种优化对用户透明,不需要添加更多配置选项。
根据我的经验,虽然主要的减速是由于数据库加载所有关系所需的多次往返;通常你可以通过确保所有关系都是懒惰来获得很好的性能提升,并为索引期间加载所需的关系启用第二级缓存。根据你的模型,缓存可能比预测更有效。
但我意识到我对实体的建模方式做了一些假设,因此您的报告非常有趣。请打开一个新的"改进" JIRA on our issue tracker。