使用hibernate search后,就会在加载hibernate配置文件时,自动在本地磁盘里建立索引文件,这个只是一个没有将数据库的记录加入到索引文件里去的,而只有一些必要信息的索引文件,因此,当我们将一个原来存在的索引文件删除后,想将它重建起来,那可以使用如下的方式来重建:
1 在重建的过程中,首先我遇到的问题是如何在使用注解的工程里面获取sessionFactory,这个使用另外加载配置文件的方式再实例化一个spring容器也是可以的,不过,这个spring容器产生的bean实例只是用到sessionFactory,而产生大量的bean实例,这若不用单例模式则很容易出现内在溢出的情况。
后来才知道,使用下面的方式可以获取sessionFactory(开始时我使用@Resource放在AnnotationSessionFactoryBean sessionFactory上面来加载它,是不对的)
@Autowired
private ApplicationContext ctx;//用它来获取上下文,其实就相当于加载了spring配置文件一样
private LocalSessionFactoryBean sessionFactory = (LocalSessionFactoryBean) ctx.getBean("&sessionFactory");//用它来获取sessionFactory就可以成功啦
获取sessionFactory的目的是为了从配置文件里读出所有的mapping对象,再进行索引文件的重建,而不用写死在代码里指明那个类要重建索引,不然当你加入一个需索引的类,而忘记在这里改,那重建里就会没有它的信息,所以这里用配置文件里的mapping对象来处理重建的问题比较好。
2 逐一加对每一个类进行加入索引操作
3 重建前要先删除索引,删除时一个没有加入索引文件的类时会发生异常,这个要处理好。
具体实现如下:
//重建索引
public void rebuildIndex() throws Exception{
Session session = getSession();
FullTextSession fullTextSession = Search.getFullTextSession( session);
fullTextSession.setFlushMode(FlushMode.MANUAL);
fullTextSession.setCacheMode(CacheMode.IGNORE);
// Transaction tx = fullTextSession.beginTransaction(); //这里是配置了事务交由spring管理,会自动开启与提交,所以这里就没开启它来
// WebApplicationContext cxt =
// WebApplicationContextUtils.getWebApplicationContext( getServletContext());
// AnnotationSessionFactoryBean factory = (AnnotationSessionFactoryBean) cxt.getBean( "&sessionFactory");
sessionFactory = (LocalSessionFactoryBean) ctx.getBean("&sessionFactory");
if(sessionFactory != null){
log.debug("sessionFactory成功从配置文件里注入");
}
else {
log.debug("sessionFactory未从配置文件里注入,它为空,重建索引操作失败!");
throw new Exception("sessionFactory未从配置文件里注入,它为空,重建索引操作失败!");
}
Iterator iter = sessionFactory.getConfiguration().getClassMappings();
while( iter.hasNext()) {//找出配置文件里写的持久化到数据库去的实体类
RootClass clz = (RootClass) iter.next();
buildClassIndex( fullTextSession, clz.getMappedClass());
}
// tx.commit(); //index are written at commit time
}
private void buildClassIndex(FullTextSession fullTextSession, Class mappedClass) {
//Scrollable results will avoid loading too many objects in memory
try {
fullTextSession.purgeAll( mappedClass);//删除索引
} catch (Exception e) {//小心要处理一些没有加入索引文件的实体而引起的异常
log.error("删除" + mappedClass + "索引的时候发生异常!可能该类没有加入索引文件。 ");
return ;
}
int BATCH_SIZE = 100;
ScrollableResults results = fullTextSession.createCriteria( mappedClass)
.setFetchSize(BATCH_SIZE).scroll( ScrollMode.FORWARD_ONLY );
int index = 0;
Object temp;
while( results.next() ) {//这个是用来遍历一个类的所有记录的,我们可以用调试的方式查看每一个results.next值,它就是每一个封装的对象
index++;
temp = results.get(0);
fullTextSession.index(temp); //index each element
if (index % BATCH_SIZE == 0) {//达到多少条记录就将它写入磁盘中,那个100是我随便设置的
fullTextSession.flush(); //apply changes to indexes
fullTextSession.clear(); //clear since the queue is processed
}
}
if(index % BATCH_SIZE != 0){//确保它们都写出到磁盘,如果是自己开启一个事务来操作的话,我们不用下面的方法,那么只有等到事务提交后,索引文件才被更新
fullTextSession.flush(); //apply changes to indexes
fullTextSession.clear(); //clear since the queue is processed
}
}
另外有关重建索引的还可以参考:
http://simonlei.iteye.com/blog/577068
http://jiangnan2112.iteye.com/blog/777917
http://isoloist.iteye.com/blog/856888