Lucene入门(2): Solr内部的合并策略

原文地址: http://java.dzone.com/news/merge-policy-internals-solr


上周,一个同事问了我一个关于solr的段合并的简单问题. 在讨论这个问题了几分钟后, 我意识到关于这个问题还有许多精细的地方值得注意, 所以我开始阅读源代码, 然后发现了一些很有意思的事情, 这也是我在这个文章将要总结的东西 .


首先, 什么是合并策略(merge policy) ?


MergePolicy是一个抽象类, 它负责挑选出哪些段需要进行合并. 这个类会产生一个MergeSpecification, MergeSpecification这个类包含了一组OneMerge对象. 每一个OneMerge对象代表一个合并(merge)动作, 这个合并动作是由即将被合并成一个大段的多个小段定义的.


当索引发生变化的时候,IndexWriter类就会调用MergePolicy去获取一个MergeSpecification. 接着, 它又调用MergeScheduler, MergeSheduler负责决定什么时候去执行合并动作. MergeScheduler主要有两个实现类: ConcurrentMergeScheduler--对于每个合并都使用单独的线程去执行, SerialMergeScheduler--在当前的线程中串行地执行所有的合并.最后,当真正执行合并的时候, IndexWriter完成部分工作, 把其他的部分工作交给SegmentMerger.


所以,如果我们想要知道什么时候多个段将要被合并, 为什么一个段会被合并而另一个不会, 以及其他的类似事情, 我们应该好好看下MergePolicy.


MergePolicy有多个实现,我主要注意到的是其中一个(LogByteSizeMergePolicy),因为它是Solr的默认实现(译者注:在最新版的solr中,默认实现是TieredMergePolicy),而且我相信它应该是被大多数人所使用的.MergePolicy定义了三个抽象方法来构造一个MergeSpecification

  • findMerges方法, 只要索引发生改变,这个方法就会被调用.这篇文章中,我会讲到这个方法
  • findMergesForOptimize,只要optimize动作执行的时候,这个方法就会被调用
  • findMergesToExpungeDeletes,只要擦除删除(expunge deletes)动作执行的时候,这个方法就会被调用
首先,我会给出一个简单的概念来描述merge policy是怎样工作的,请看下面:
1.根据名称对段进行排序
2.将现有的段分成不同的组(levels).每个组都包含连续的多个段.
3.对每一组,计算出将要合并的段 之间的间隔.

参数 :
我们先定义一组参数,这些参数会在段合并的过程中用到:
  • mergeFactor:这个参数决定了许多事情,比如多少个段会被合并到一个新段中,在一个组(level)中最多能放入多少个段,以及每个组(level)的跨度.可以在solrconfig.xml中设置.
  • minMergeSize:所有小于这个参数值的段都属于同一个组(level).这个值是固定的.
  • maxMergeSize:所有大于这个参数值的段都不会被合并.这个值也是固定的.
  • maxMergeDocs:所有包含大于这个参数值的document的段都不会被合并.可以在solrconfig.xml中设置这个参数.
构造组(levels)
我们先看看组(levels)是怎么构造的.为了定义第一个组, 算法搜索到最大的段的大小. 我们把这个值叫做levelMaxSize,如果这个值比minMergeSize还小,那么我们可以认为所有的段都在一个组里. 否则, 我们定义levelMinSize 为
max\left(\frac{levelMaxSize}{mergeFactor^{0.75}}, minMergeSize\right)

这是一个相当难看的数学公式, 但是它代表了这个含义:levelMinSize大概会比levelMaxSize小mergeFactor倍(如果0.75换成1的话,levelMinSize就正好是levelMaxSize的mergeFactor分之一),但是当它比minMergeSize还小的时候,就让它等于minMergeSize.

经过这个计算之后,算法就开始挑选哪些段属于当前的组(level).我们先找到大于等于levelMinSize的最新的段,这个段和所有比它老的段,就属于这个组(level).
下一个组的构造方法使用相同的算法,但是范围会局限在 比上一组中最新的段 更新的段 中.

但是在某些情况下,如果你不知道间隔的话,这个算法会导致一个意外的组(levels)的结构.比如下面的段, 假设mergeFactor=10 and minMergeSize=1.6MiB:

段大小:
 

这种情况下有多少个组(level) ? 让我们看下, 最大的段大小 为200MB, 因此, levelMinSize就为35MB. 最新的大于levelMinSize的段是x,所以第一个组(leve)就包含x和所有比x老的组. 这就意味着只有一个组!


挑选哪些段合并


在决定了组(levels)后, MergePolicy就将挑选要合并的段.为了完成这个, 它会分别分析每个组(level). 如果一个组(level)中的段个数小于mergeFactor,那么它就会跳过这个组(level).否则,每个组就会被合并成一个新的段.如果一个组中至少一个段的大小大于maxMergeFactor,或者包含多于maxMergeDocs个document,那么这个组就会被跳过.


回到前面的第二个例子,这儿只有一个组,合并的结果将是:



minMergeSize and maxMergeSize

本文中,我已经提到过合并过程中起作用的这两个参数,它们的值在Lucene的源代码中是被写死的,它们的值分别是:

  • minMergeSize:1.6MB.这意味着任何小于1.6MB的段都会被包含在最后一个组(level)里
  • maxMergeSize:2GB.这意味着任何大于2GB的段永远都不会被合并.
结论
尽管这个算法本身并会特别复杂,但是如果你想知道在添加文档的时候,你的索引里面发生了什么,你就需要理解这里面的原理.而且,了解了合并策略怎样工作,也会帮助你设置一些参数值比如mergeFactor 和maxMergeDocs.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值