`
rockelixir
  • 浏览: 309539 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Lucene 控制segments策略

阅读更多
Lucene的索引文件,会包含很多个segments文件,每个segment中包含多个documents文件,一个segment中会有完整的正向索引和反向索引。
在搜索时,Lucene会遍历这些segments,以segments为基本单位独立搜索每个segments文件,而后再把搜索结果合并。

建立索引文件的过程,实际就是把documents文件一个个加入索引中,Lucene的做法是最开始为每个新加入的document独立生成一个segment,放在内存中。而后,当内存中segments数量到达一个阙值时,合并这些segments,新生成一个segment加入文件系统的segments列表中。
而当文件系统的segments数量过多时,势必影响搜索效率,因此需要不断合并这些segments文件。

那么Lucene的合并策略是什么?如何保证合适的segments数量呢?

其实Lucene有两套基本的策略:
第一种策略实现代码位于IndexWriter#optimize()函数,其实就是把所有segments文件合并成一个文件。合并的算法是递归合并列表最后的mergeFactor个segments文件直到合并成一个文件。这儿mergeFactor是Lucene的一个参数。
btw: 从算法细节上看,其实我不是喜欢这段实现,因为列表的最后mergeFactor个文件内容实际被扫描了segmens_count/mergeFactor次。如果分段归纳合并的方式不知道是否更好,每个segment文件内容都将被扫描 ceil(Log_mergeFactor(segmens_count)) 或ceil(Log_mergeFactor(segmens_count)) +1次,是否更好?

第二种策略实现代码位于IndexWriter#maybeMergeSegments()函数中,这个代码就复杂了,它的基本策略就是要求确保合并后两个公式的成立:
假定segments是个有序列表,B表示maxBufferedDocs,f(n)=ceil(log_M(ceil(n/B))),M表示mergeFactor,这儿maxBufferedDocs和mergeFactor是两个参数
1. 如果第i个segment的documents数量为x,第i+1个segment的documents数量为y,那么f(x)>f(y)一定成立
2. f(n)值相同的segments的数量不得超过M。
那么maybeMergeSegments()函数是如何确保这两个公式成立的呢?
1.首先,从代码:
   
protected final void maybeFlushRamSegments() throws IOException {
        // A flush is triggered if enough new documents are buffered or
        // if enough delete terms are buffered
        if (ramSegmentInfos.size() >= minMergeDocs
                || numBufferedDeleteTerms >= maxBufferedDeleteTerms) {
            flushRamSegments();
        }
    }

这儿minMergeDocs=maxBufferedDocs, 因此可以看出,当内存中缓存的segments被合并写回磁盘时生成的segment的document count等于或小于maxBufferedDocs(即minMergeDocs)。
补充:因为maybeMergeSegments()运行在同步代码中,因此只要ramSegmentInfos.size==minMergerDocs(即maxBufferedDocs)就会写回磁盘,因此应该不存在ramSegmentInfos.size>maxBufferedDocs才写回的情况。而且,但如果是这种情况,因为合并后的segment文件的document count过大,后面的maybeMergeSegments()将不做合并处理直接退出,上述公式就可能不成立,那么算法将有错。
----
2.
(1) 因此maybeMergeSegments()第一次执行时,所有segments的document count都小于等于maxBufferedDocs。此时,从i=0开始,合并i~i+mergeFactor-1个文件,如果合并后的doc count>maxBufferedDocs时,保留第i个segment,否则继续合并改变后的i~i+mergeFactor-1,直到doc count>maxBufferedDocs或所有segments文件个数已经<mergeFactor了。经过这样一轮的合并,除了最后<mergeFactor个的doc counts<=maxBufferedDocs文件外,其它文件的doc counts一定都>maxBufferedDocs并<maxBufferedDocs*mergeFactor了。
(2) 这时,不理会最后<mergeFactor个doc count<maxBufferedDocs的文件,而后按2.1的同理规则,合并之前的文件,让这些文件的最后<mergerFactor个segment符合 maxBufferedDocs<doc counts<=maxBufferedDocs*mergeFactor,之前的segment文件都符合maxBufferedDocs*mergeFactor<doc counts<=maxBufferedDocs*mergeFactor^2
(3) 重复2.2,最后得到的列表就会满足上述两等式的成立

3.之后,每次从内存缓存中flush出一个新的segment时,也就是往这个segments列表的最后增加一个doc_count<=maxBufferedDocs的文件,同样执行上述步骤2进行合并,能够始终保证上述两公式的成立。

4.
(1)IndexWriter#addIndexesNoOptimize同样借鉴使用了maybeMergeSegments()算法,区别此时,实际是已有一个符合两公式的segments序列T,在T之后追加上随意顺序的segments序列S。这时,我们先找到S中doc count值最大的那个segment,计算出它属于的区间f(x),使得maxBufferedDocs*mergeFactor^x<doc counts<=maxBufferedDocs*mergeFactor^(x+1),而后按2.2的算法合并出除了最后<mergerFactor个segments外, 之前所有segments都符合 a. doc count>maxBufferedDocs*mergeFactor^(x+1) b.符合上述2等式。
btw: 因为这儿调用IndexWriter#addIndexesNoOptimize传入的参数是maxBufferedDocs*mergeFactor^(x+1),因为S所有segment的doc count都一定小于maxBufferedDocs*mergeFactor^(x+1),因此S的所有元素都会参与收缩合并。
(2)将最后<mergerFactor个doc count<maxBufferedDocs*mergeFactor^(x+1)的segments合并,如果合并后的segment的doc count大于maxBufferedDocs*mergeFactor^(x+1),就继续2.2步骤,使得整个队列符合上述两公式

上述两种策略,最终确保了Lucene中的segments不会太多,确保效率。

BTW:实际上,如果documents太多时,Lucene还支持把docuements分成几个组,每个组用独立的进程或电脑进行索引,而后再多个目录的索引合并起来,具体可参考IndexWriter#addIndexesNoOptimize和IndexWriter#addIndexes函数
分享到:
评论

相关推荐

    基于Lucene的搜索策略研究

    基于Lucene的搜索策略研究

    针对中文检索的Lucene改进策略

    针对中文检索的Lucene改进策略 为了提高基于Lucene中文检索系统的检索精度和效率,通过分析Lucene的结构,在系统中加入了中文分词模块和索引 文档预处理模块。给出了具体的实验方法和实验过程,对改进原理和实验数据...

    lucene实例lucene实例

    lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例lucene实例

    lucene,lucene教程,lucene讲解

    lucene,lucene教程,lucene讲解。 为了对文档进行索引,Lucene 提供了五个基础的类 public class IndexWriter org.apache.lucene.index.IndexWriter public abstract class Directory org.apache.lucene.store....

    lucene3.0 lucene3.0

    lucene3.0 lucene3.0 lucene3.0 lucene3.0 lucene3.0

    lucene学习lucene学习

    lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习lucene学习...

    Lucene3.0特性,Lucene3.0特性

    Lucene3.0特性Lucene3.0特性

    lucene讲义 叫你用lucene算法

    lucene学习教程lucene讲义 叫你用lucene算法

    ssm+lucene

    ssm+lucene

    lucene3源码分析

    lucene3源码分析

    lucene.NET 中文分词

    lucene.NET 中文分词 高亮 lucene.NET 中文分词 高亮 lucene.NET 中文分词 高亮 lucene.NET 中文分词 高亮

    lucene6.6jar包

    lucene

    Annotated Lucene 中文版 Lucene源码剖析

    Annotated Lucene 中文版 Lucene源码剖析

    lucene详细使用教程

    lucene

    Lucene实战

    《Lucene实战(第2版)》基于Apache的Lucene 3.0,从Lucene核心、Lucene应用、案例分析3个方面详细系统地介绍了Lucene,包括认识Lucene、建立索引、为应用程序添加搜索功能、高级搜索技术、扩展搜索、使用Tika提取文本...

    lucene-core-7.7.0-API文档-中文版.zip

    赠送jar包:lucene-core-7.7.0.jar; 赠送原API文档:lucene-core-7.7.0-javadoc.jar; 赠送源代码:lucene-core-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-core-7.7.0.pom; 包含翻译后的API文档:lucene...

    Lucene4.X第九讲-Lucene搜索深入实战

    本课程由浅入深的介绍了Lucene4的发展历史,开发环境搭建,分析lucene4的中文分词原理,深入讲了lucenne4的系统架构,分析lucene4索引实现原理及性能优化,了解关于lucene4的搜索算法优化及利用java结合lucene4实现...

    lucene4.2 jar包

    lucene-analyzers-common-4.2.0.jar; lucene-analyzers-kuromoji-4.2.0.jar; lucene-analyzers-phonetic-4.2.0.jar; lucene-codecs-4.2.0.jar; lucene-core-4.2.0.jar; lucene-grouping-4.2.0.jar; lucene-...

    Lucene 使用正则表达式

    Lucene 正则表达式 regexQuery

    Lucene时间区间搜索

    c#下实现Lucene时间区间查询匹配。主要还是对Lucene查循对像Query的实现

Global site tag (gtag.js) - Google Analytics