lucene 4.x 近实时搜索


请支持原创博客 http://blog.csdn.net/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 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(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进行归并排序,是一个读出,合并再生

成的过程。

你可能感兴趣的:(lucene)