lucene 4.x 近实时搜索

Lucene 4.x中,nrtmanager已被ControlledRealTimeReopenThread取代以实现近实时搜索。通过每次从IndexWriter获取新reader,可以确保搜索到最新内容。flush操作代价小,而commit是重量级的,涉及硬盘操作和segment的合并,归并排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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

成的过程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值