[原]Lucene系列-近实时搜索

标签: | 发表时间:2015-01-21 04:01 | 作者:whuqin
出处:http://blog.csdn.net/whuqin

近实时搜索(near-real-time)可以搜索IndexWriter还未commit的内容,介于immediate和eventual之间,在数据比较大、更新较频繁的情况下使用。lucene的nrt可以控制更新生效的间隔时间。

基本过程:

  • 打开indexwriter
  • 从indexwriter中获得indexreader
  • 建立indexsearcher
  • 查看是否有变化,有变化则建立新reader/searcher

需要用到DirectoryReader.openIfChanged函数,该函数会对老readers做删除、合并,将变化应用到新reader中。代码如下,基于lucene 4.10。

    private Directory ramDir = new RAMDirectory();
    public void testNrt() throws IOException {
        //IndexWriter
        IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_0, new StandardAnalyzer());
        IndexWriter writer = new IndexWriter(ramDir, writerConfig);

        Document doc = new Document();
        doc.add(new TextField("title", "lucene", Field.Store.YES));
        doc.add(new TextField("author", "zhangsan", Field.Store.YES));
        writer.addDocument(doc);
        //IndexReader,基于IndexWriter打开的IndexReader
        <strong>IndexReader reader = DirectoryReader.open(writer, true);</strong>
        IndexSearcher searcher = new IndexSearcher(reader);
        
        TermQuery query = new TermQuery(new Term("title", "lucene"));
        TopDocs docs = searcher.search(query, 10);
        System.out.println(docs.totalHits);

        for (int i = 0; i < 10; ++i) {
            doc = new Document();
            doc.add(new TextField("title", "lucene " + i, Field.Store.YES));
            doc.add(new TextField("author", "zhangsan " + i, Field.Store.YES));
            writer.addDocument(doc);
        }
        //openIfChanged,如果有提交或未提交的变化,就打开新的indexreader。
        <strong>IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) reader, writer, true);</strong>
        if (reader != newReader) {
            searcher = new IndexSearcher(newReader);
            reader.close();
        }

        docs = searcher.search(query, 10);
        System.out.println(docs.totalHits);
    }

在实际应用中,会并行的进行搜索、建索引、打开新Reader,需要考虑多线程安全问题。lucene提供了SearcherManager extends ReferenceManager<IndexSearcher>来确保searcher和索引的使用安全。

  • accquire获取最新的IndexSearcher引用
  • release释放不用的searcher,以便于SearcherManager关闭不再使用的老IndexSearcher
  • maybeRefresh,起一个后台线程定期调用该方法,以获得包含了变化的新IndexSearcher
追踪maybeRefresh代码会看到里面还是调用了 DirectoryReader.openIfChanged方法来获取新reader,只是加了多线程安全控制,封装了reader/searcher的生成。

    private Directory ramDir = new RAMDirectory();
    public void testNrt() throws IOException {
        //IndexWriter
        IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_0, new StandardAnalyzer());
        IndexWriter writer = new IndexWriter(ramDir, writerConfig);

        Document doc = new Document();
        doc.add(new TextField("title", "lucene", Field.Store.YES));
        doc.add(new TextField("author", "zhangsan", Field.Store.YES));
        writer.addDocument(doc);

        //可以自定义SearcherFactory来对生成的IndexSearcher进行设置,如setSimilarity
        <strong>SearcherManager searcherManager = new SearcherManager(writer, true, new SearcherFactory());</strong>
        //获取当前Searcher
        <strong>IndexSearcher searcher = searcherManager.acquire();</strong>

        TermQuery query = new TermQuery(new Term("title", "lucene"));
        TopDocs docs = searcher.search(query, 10);
        System.out.println(docs.totalHits);
        //减少该searcher的引用,本质是利用了IndexReader的refCount,当refCount为0时关闭reader
        <strong>searcherManager.release(searcher);</strong>

        for (int i = 0; i < 10; ++i) {
            doc = new Document();
            doc.add(new TextField("title", "lucene " + i, Field.Store.YES));
            doc.add(new TextField("author", "zhangsan " + i, Field.Store.YES));
            writer.addDocument(doc);
        }
        //调用DirectoryReader.openIfChanged获取新searcher
        searcherManager.maybeRefresh();

        searcher = searcherManager.acquire();
        docs = searcher.search(query, 10);
        System.out.println(docs.totalHits);
        searcherManager.release(searcher);
        //释放资源
        <strong>searcherManager.close();</strong>

作者:whuqin 发表于2015/1/20 20:01:33 原文链接
阅读:110 评论:0 查看评论

相关 [lucene 系列 实时] 推荐:

[原]Lucene系列-近实时搜索

- - 文武天下
近实时搜索(near-real-time)可以搜索IndexWriter还未commit的内容,介于immediate和eventual之间,在数据比较大、更新较频繁的情况下使用. lucene的nrt可以控制更新生效的间隔时间. 从indexwriter中获得indexreader. 建立indexsearcher.

[原]Lucene系列-facet

- - 文武天下
facet:面、切面、方面. 个人理解就是维度,在满足query的前提下,观察结果在各维度上的分布(一个维度下各子类的数目). 如jd上搜“手机”,得到4009个商品. 其中品牌、网络、价格就是商品的维度(facet),点击某个品牌或者网络,获取更细分的结果. 点击品牌小米,获得小米手机的结果,显示27个.

[原]Lucene系列-FieldCache

- - 文武天下
域缓存,加载所有文档中某个特定域的值到内存,便于随机存取该域值. 当用户需要访问各文档中某个域的值时,IndexSearcher.doc(docId)获得Document的所有域值,但访问速度比较慢,而且只能获得Stored域的值. FieldCache能获得域值数组,根据docId random access域值.

[原]Lucene系列-索引文件

- - 文武天下
本文介绍下lucene生成的索引有哪些文件组成,每个文件包含了什么信息. 基于Lucene 4.10.0. 索引(index)包含了存储的文档(document)正排、倒排信息,用于文本搜索. 索引又分为多个段(segments),每个新添加的doc都会存到一个新segment中,不同的segments又会合并成一个segment.

有关Lucene的问题(7):用Lucene构建实时的索引

- -
由于前一章所述的Lucene的事务性,使得Lucene可以增量的添加一个段,我们知道,倒排索引是有一定的格式的,而这个格式一旦写入是非常难以改变的,那么如何能够增量建索引呢. Lucene使用段这个概念解决了这个问题,对于每个已经生成的段,其倒排索引结构不会再改变,而增量添加的文档添加到新的段中,段之间在一定的时刻进行合并,从而形成新的倒排索引结构.

有关Lucene的问题(8):用Lucene构建实时索引的文档更新问题

- -
在有关Lucene的问题(7),讨论了使用Lucene内存索引和硬盘索引构建实时索引的问题. 然而有的读者提到,如果涉及到文档的删除及更新,那么如何构建实时的索引呢. 1、Lucene删除文档的几种方式. IndexReader.deleteDocument(int docID)是用 IndexReader 按文档号删除.

用Lucene构建实时索引的文档更新问题

- - 开源软件 - ITeye博客
1、Lucene删除文档的几种方式. IndexReader.deleteDocument(int docID)是用 IndexReader 按文档号删除. IndexReader.deleteDocuments(Term  term)是用 IndexReader 删除包含此词(Term)的文档. IndexWriter.deleteDocuments(Term  term)是用 IndexWriter 删除包含此词(Term)的文档.

lucene排序

- - 开源软件 - ITeye博客
排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最高或卖的最好的商品,再比如在Iteye里的博客栏里,每天都会以降序的方式,来显示出最新发出的几篇博客,有了排序,我们就能在某些时候很方便快速的得到某些有效信息,所以说排序功能,无处不在 ^_^.

Lucene 使用教程

- - 行业应用 - ITeye博客
1 lucene简介 . 1.1 什么是lucene . Lucene是一个全文搜索框架,而不是应用产品. 因此它并不像 http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品. 1.2 lucene能做什么 . 要回答这个问题,先要了解lucene的本质.

Lucene 4.x 之 IndexReader

- - zzm
在Lucene 3.x时代,《Lucene In Action》是一本相当不错的参考书,书中详细介绍了Lucene各种高级使用技术,对于开发者来说非常实用. 但是近期Lucene升级到了4.x版本,在性能等各方面有了很大的提高,值得在新项目中使用. 然而Lucene 4.x中的API相比3.x来说有了很大的改变,《Lucene In Action》中的很多内容都已经过时了,并且由于4.x推出的时间不长,还没有比较好的文档来对用法进行说明,这个系列文章就是想记录下自己使用Lucene 4.x的经验体会,供大家参考使用.