打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Lucene?near?real?time?search

Lucene near real time search

(2011-02-10 16:01:06)
标签:

杂谈

分类: 工作,积累

   在2.9之前,要看到index writer上发生的更新,必须关闭indexwriter,关闭动作会导致内部缓存的更新操作(生成新的segment,flush和commit,在硬盘上生成对应文件),然后再打开新的reader,才能看到更新。从2.9开始,Lucene开始引入nearrealtime search,可以在不关闭index writer的情况下,搜索到更新的内容。

实现原理

    Nearreal time search的原理记录在LUCENE-1313和LUCENE-1516里。LUCENE-1313,在IndexWriter内部维护了一个ram directory,在内存够用前,flush和merge操作只是把数据更新到ramdirectory,只有Index Writer上的optimize和commit操作才会导致ramdirectory上的数据完全同步到文件。LUCENE-1516,IndexWriter提供了实时获得reader的API,这个调用将导致flush操作,生成新的segment,但不会commit(fsync),从而减少了IO。新的segment被加入到新生成的reader里。从返回的reader里,可以看到更新。所以,只要每次新的搜索都从IndexWriter获得一个新的reader,就可以搜索到最新的内容。这一操作的开销仅仅是flush,相对commit来说,开销很小。

   这里要清楚几个概念:lucene的index组织和flush,commit,optimize操作。
  • Lucene的index组织方式为一个index目录下的多个segment。新的doc会加入新的segment里,这些新的小segment每隔一 段时间就合并起来。因为合并,总的segment数量保持的较小,总体search速度仍然很快。为了防止读写冲突,lucene只创建新的 segment,并在任何active的reader不在使用后删除掉老的segment。
  • flush是把数据写入到操作系统的缓冲区,只要缓冲区不满,就不会有硬盘操作。
  • commit是把所有内存缓冲区的数据写入到硬盘,是完全的硬盘操作。
  • optimize是对多个segment进行合并,这个过程涉及到老segment的重新读入和新segment的合并,属于CPU和IO-bound的 重量级操作。这是因为,Lucene索引中最主要的结构posting通过VINT和delta的格式存储并紧密排列。合并时要对同一个term的 posting进行归并排序,是一个读出,合并再生成的过程。

代码解读(基于Lucene3.0)

   在IndexWriter获得reader的方法中,主要调用了两个方法doflush()和maybeMerge()。doflush()将调用DocumentsWriter的flush方法,生成新的segment,返回的reader将能访问到新的segment。DocumentsWriter接收多个document添加,并写入到同一个segment里。每一个加入的doc会经过多个DocConsumer组成的流水线,他们包括StoredFieldsWriter(内部调用FieldsWriter),TermVectorsTermsWriter,FreqProxTermsWriter,NormsWriter等。在外界没有主动调用flush的情况下,RAMbuffer全用完了或者加入的doc数足够大后,才会创建新的segment并flush到目录中。

   FreqProxTermsWriter调用TermHashPerField负责term的索引过程,当索引某字段词项时,使用对应TermsHashPerField的add()函数完成(一个)词项索引过程,并将索引内容(词项字符串/指针信息/位置信息等)存储于内存缓冲中。中间的过程使用了CharBlockPool,IntBlockPool,ByteBlockPool,只要内存够用,可以不断往后添加。

特性实验

   设计一个文档检索程序,进程管理一个indexwriter和两个线程,线程A负责新文档的索引,线程B负责处理搜索请求,其中搜索时使用IndexWriter的新API获取新的reader。通过交替的生成index和search的请求,观察search的结果和索引目录的变化。实验结果如下:

  1. 打开indexwriter时,会生成一个lock文件
  2. 每次调用reader时,如果发生了更新,会先进行一次flush,把上次积攒在内存中的更新数据写成新的segment,多出一个.cfs。
  3. 从新的reader中,可以读到之前新加入的doc信息。
  4. 当新生成的segment达到十次后,会发生一次optimize,生成8个文件,为.fdt, .fdx, .frq, .fnm, .nrm, .prx, .tii, .tis。
  5. 当然,外界也可以主动触发optimize,结果是一样的。optimize前的多个segment的文件以及此前optimize的文件不再有用。
  6. 因为optimize生成cfs要消耗双倍磁盘空间,并增加额外的处理时间,当optimize的index大小较大,超过了index总大小的10或者一个规定大小时,即使index writer指定了CFS格式,optimize仍然会保留为多个文件的格式(LUCENE-2773)。
  7. 调用indexwriter的close方法,lock文件会被释放,但除了optimize的结果文件外,此前生成的文件并不会被删除。只到下次打开此index目录时,不需要的文件才会被删除。
  8. 当三种情况下,indexwriter会试图删除不需要的文件,on open,on flushing a new segment,On finishing a merge。但如果当前打开的reader正在使用文件,则不会删除。
  9. 因此,reader使用完后,一定要调用close方法,释放不需要的文件。

改进计划

In the future NRT may involve searching directly on the rambuffer without first encoding a full Lucene segment


参考资料
lucene官方对于near real time search的介绍
http://wiki.apache.org/lucene-java/NearRealtimeSearch

lucene-2.9.0 索引过程
http://blog.csdn.net/todaylxp/archive/2009/10/25/4726017.aspx

lucene的内存存储posting结构,增量式的posting内存存储结构,通过不同级别的多个内存块实现动态增加:
http://lucene-group.group.javaeye.com/group/blog/587120
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Lucene.net 系列三 --- index(中)
lucene相关博客
lucene 全文检索简介
影响Lucene索引速度原因及提高速度技巧
影响Lucene索引速度原因以及提高索引速度技巧[转]
Lucene里经常被聊到的几个话题【基础】
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服