请支持原创博客 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进行归并排序,是一个读出,合并再生
成的过程。