请支持原创博客 http://blog.youkuaiyun.com/cl59452/article/details/38408741
lucene2.9 之后推出了nrtmanager 近实时搜索,但是很多人在lucene4.x 中找不到了,我通过查阅apache 的log 发现,lucene已经用ControlledRealTimeReopenThread将nrtmanager替代了具体的实现过程如下:
public class IndexUtil {
private SearcherManager mgr;
private IndexWriter writer;
private TrackingIndexWriter tkWriter;
private ControlledRealTimeReopenThread<IndexSearcher> crtThread;
// private String path ;
public IndexUtil(String path){
try {
Directory fsDir = FSDirectory.open(new File(path));
//创建writer
writer = new IndexWriter(fsDir,new IndexWriterConfig(Version.LUCENE_47,new IKAnalyzer(true)));
//新建SearcherManager
//true 表示在内存中删除,false可能删可能不删,设为false性能会更好一些
mgr = new SearcherManager(writer,false,new SearcherFactory());
//ControlledRealTimeReopenThread 构造是必须有的,主要将writer装,每个方法都没有commit 操作。
tkWriter = new TrackingIndexWriter(writer);//为writer 包装了一层
//创建线程,线程安全的,我们不须处理
crtThread = new ControlledRealTimeReopenThread<IndexSearcher>(tkWriter, mgr, 5.0, 0.025);
crtThread.setDaemon(true);//设为后台进程
crtThread.setName("我是好人");
crtThread.start();//启动线程
// crtThread.
} catch (IOException e) {
e.printStackTrace();
}
}
public void search(){
IndexSearcher searcher = null;
try {
//更新看看内存中索引是否有变化如果,有一个更新了,其他线程也会更新
mgr.maybeRefresh();
//利用acquire 方法获取search,执行此方法前须执行maybeRefresh
searcher = mgr.acquire();
IndexSearcher tr = mgr.refreshIfNeeded(searcher);
String fields[] = {"body","name"};
QueryParser qp = new MultiFieldQueryParser(Version.LUCENE_47,fields,new IKAnalyzer(true));
Query query =new TermQuery(new Term("id", "2"));// qp.parse("中国");
TopDocs tds = searcher.search(query, 5);
ScoreDoc[] sds = tds.scoreDocs;
for(ScoreDoc sd:sds){
Document d = searcher.doc(sd.doc);
System.out.println(d.get("name")+d.get("body")/*+d.get("id")*/);
}
} catch (IOException e) {
e.printStackTrace();
} /*catch (ParseException e) {
e.printStackTrace();
}*/finally{
try {
//释放searcher,
mgr.release(searcher);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("------------------------------------------------------------------------------------------------");
}
}
}
只有Index Writer上的commit操作才会导致ram directory上的数据完全同步到文件。Index Writer提供了实时获得reader的API,这个调用将导致flush操作,生成新的segment,但不会commit(fsync),从而减少 了IO。新的segment被加入到新生成的
reader里。从返回的reader里,可以看到更新。所以,只要每次新的搜索都从IndexWriter获得一个新的reader,就可以搜索到最新的内容。这一操作的开销仅仅是flush,相对commit来说,开销很小。
Lucene的index组织方式为一个index目录下的多个segment。新的doc会加入新的segment里,这些新的小segment每隔一段时间就合并起来。因为合并,总的segment数
量保持的较小,总体search速度仍然很快。为了防止读写冲突,lucene只创建新的segment,并在任何active的reader不在使用后删除掉老的segment。
flush是把数据写入到操作系统的缓冲区,只要缓冲区不满,就不会有硬盘操作。
commit是把所有内存缓冲区的数据写入到硬盘,是完全的硬盘操作。
重量级操作。这是因为,Lucene索引中最主要的结构posting通过VINT和delta的格式存
储并紧密排列。合并时要对同一个term的posting进行归并排序,是一个读出,合并再生
成的过程。