一直觉得lucene的reopen有问题,今天特地研究了下,顺便熟悉了整个IndexReader的结构体系
IndexReader是一个体系,他是search的核心io之一
org.apache.lucene.index
Class IndexReader
java.lang.Object org.apache.lucene.index.IndexReader
-
Direct Known Subclasses:
-
FilterIndexReader,
MultiReader,
ParallelReader
先来看看IndexReader下面的类体系我们平常会使用的三个派生: FilterIndexReader MultiReader ParallelReader
下面来看看我犯错误的reopen:
public IndexReader reopen() throws CorruptIndexException, IOException
之前为什么我错了,我以为这个方法是自省的(根本没有注意它的返回不是void的道理么...),所以我怎么写的?
iSearch.getIndexReader().reopen();
误以为这样就可以reopen,结果总是被投诉没有更新,所以一直觉得更新有问题,实际上是我用法的问题,应该是这样的.
if (iSearch != null) {
// 新修改的reopen方法
try {
IndexReader irOld = this.reOpen(iSearch);
// isearchMap.remove(searchBean.getIsearchName());
isearchMap.put(searchBean.getIsearchName(),
new IndexSearcher(irOld));
} catch (Exception e) {
e.printStackTrace();
} finally {
// 注意要关闭掉原来的iSearch
iSearch.close();
iSearch = null;
logger.info(">>>>>>>>>>>>>one search has been reopen:"
+ searchBean.getIsearchName());
}
}
上面是从程序里截取的看看意思就好了.
但后来发现这样还是不对的,看源码上的说明:
If the index has not changed since this instance was (re)opened, then this
* call is a NOOP and returns this instance. Otherwise, a new instance is
* returned. The old instance is <b>not</b> closed and remains usable.
如果没有改变的话,他会返回null的,这样不得不判断一下,所以代码要这样:
if (iSearch != null) {
// 新修改的reopen方法
try {
IndexReader irOld = reOpen(iSearch);
if (irOld != null) {
// isearchMap.remove(searchBean.getIsearchName());
isearchMap.put(searchBean.getIsearchName(),
new IndexSearcher(irOld));
// 注意要关闭掉原来的iSearch
iSearch.close();
iSearch = null;
}
} catch (Exception e) {
logger.error(e);
} finally {
logger.info(">>>>>>>>>>>>>one search has been reopen:"
+ searchBean.getIsearchName());
}
}
这样可以在索引不变下不产生更多io消耗,那么我们可以这样理解reopn的实质:
首先判断 lastmodify时间,如果被更新了则, new 一个IndexReader, 否则就直接返回null,而操作方法都扔给了用户. 所以官方所谓的reopen能减少消耗说法并不准确,它做的只是在改变时重新连接,但这个他官方文档所说的只更新更新部分有很大不同,现在只是选择性地降低了io,但是如果每次探测时索引都变了就变得没有意义,这样的好吃是,索引的跟踪可以变得更频繁,也不再需要程序过多干预了.
但是目前这个方法写得不够成熟,至少我认为应该更"傻瓜"而不是把那么多细节都扔给开发者.
好了reopen这个新兴方法应该算是彻底搞明白了,原来看似吹嘘的很神的新东西,还是老瓶子装新酒呀,呵呵....
末了,代码再完善下:
if (iSearch != null) {
// 新修改的reopen方法
Boolean isNew = false;
try {
IndexReader irOld = reOpen(iSearch);
if (irOld != null) {
isNew = true;
// isearchMap.remove(searchBean.getIsearchName());
isearchMap.put(searchBean.getIsearchName(),
new IndexSearcher(irOld));
}
} catch (Exception e) {
logger.error(e);
} finally {
if (isNew) {
//保证关闭掉资源,否则连接数一多把机器io挂死
iSearch.close();
iSearch = null;
}
logger.info(">>>>>>>>>>>>>one search has been reopen:"
+ searchBean.getIsearchName());
}