索引段和合并

Lucene 索引存储在段中,Solr 提供了几个参数来控制如何编写新段以及何时合并段。

Lucene 索引是“一次性写入”文件:一旦一个段被写入永久存储(磁盘),它将永远不会被更改。这意味着索引实际上由几个文件组成,每个文件都是完整索引的子集。为了防止索引的永久碎片化,段会定期合并。

solrconfig.xml 中的 <indexConfig>

solrconfig.xml 中的 <indexConfig> 部分定义了 Lucene 索引编写器的底层行为。

默认情况下,Solr 附带的示例 solrconfig.xml 中的设置已注释掉,这意味着使用了默认值。在大多数情况下,默认值都是可以的。

<indexConfig>
  ...
</indexConfig>

写入新段

以下元素可以在 <indexConfig> 元素下定义,并定义何时将新段写入(“刷新”)到磁盘。

ramBufferSizeMB

一旦累积的文档更新超过此内存空间(以兆字节为单位),则会刷新待处理的更新。这还可以创建新段或触发合并。通常,使用此设置优于 maxBufferedDocs。如果在 solrconfig.xml 中同时设置了 maxBufferedDocsramBufferSizeMB,那么当达到任一限制时,都会发生刷新。默认值为 100 MB。

<ramBufferSizeMB>100</ramBufferSizeMB>

maxBufferedDocs

设置在内存中缓冲的文档更新数量,然后将它们作为新段刷新。这还可能触发合并。默认的 Solr 配置设置为按 RAM 使用情况(ramBufferSizeMB)刷新。

<maxBufferedDocs>1000</maxBufferedDocs>

useCompoundFile

控制新写入(尚未合并)的索引段是否应使用 复合文件段 格式。默认值为 false

<useCompoundFile>false</useCompoundFile>

ramPerThreadHardLimitMB

设置每个线程的最大内存(以兆字节为单位)消耗,如果超过该值,则会触发强制刷新。给定值必须大于 0 且小于 2048 MB(2GB)。

<ramPerThreadHardLimitMB>1945</ramPerThreadHardLimitMB>
这是一个专家级参数,因为它会触发强制刷新,即使 ramBufferSizeMB 尚未超过。

合并索引段

以下设置定义了合并段的时间。

mergePolicyFactory

定义合并段的方式。

Solr 中的默认设置是使用 `TieredMergePolicy`,该策略合并大小大致相等的段,但每个层级允许的段数有限。

其他可用的策略包括 `LogByteSizeMergePolicy` 和 `LogDocMergePolicy`。有关这些策略的更多信息,请参阅 MergePolicy javadocs

<mergePolicyFactory class="org.apache.solr.index.TieredMergePolicyFactory">
  <int name="maxMergeAtOnce">10</int>
  <int name="segmentsPerTier">10</int>
  <double name="forceMergeDeletesPctAllowed">10.0</double>
  <double name="deletesPctAllowed">33.0</double>
</mergePolicyFactory>

控制段大小

用户对 `TieredMergePolicy`(或 `LogByteSizeMergePolicy`)配置进行的最常见调整是“合并因子”,用于更改一次合并的段数,以及在 `TieredMergePolicy` 的情况下,合并段的最大大小。

对于 `TieredMergePolicy`,可以通过设置 `maxMergeAtOnce`(默认值为 `10`)、`segmentsPerTier`(默认值为 `10`)和 `maxMergedSegmentMB`(默认值为 `5000`)选项来控制。

LogByteSizeMergePolicy 有一个 `mergeFactor` 选项(默认值为 `10`)。

要了解这些选项为何重要,请考虑使用 `LogByteSizeMergePolicy` 对索引进行更新时会发生什么情况:文档始终添加到最近打开的段中。当一个段填满时,将创建一个新段,后续更新将放置在那里。

如果创建新段会导致最低级别段的数量超过 `mergeFactor` 值,那么所有这些段将合并在一起以形成一个大段。因此,如果合并因子为 `10`,则每次合并都会创建一个大段,该大段大约是其十个组成部分的十倍。当有 10 个这样的较大段时,它们又会合并成一个更大的单段。此过程可以无限期地继续下去。

使用 `TieredMergePolicy` 时,该过程是相同的,但不是使用单个 `mergeFactor` 值,而是使用 `segmentsPerTier` 设置作为决定是否应进行合并的阈值,而 `maxMergeAtOnce` 设置确定应在合并中包含多少个段。

选择最佳合并因子通常是索引速度与搜索速度之间的权衡。索引中段越少,搜索速度通常越快,因为需要查找的地方越少。它还可以减少磁盘上的物理文件数量。但为了保持段数较低,合并会更频繁地发生,这会增加系统负载并减慢对索引的更新速度。

相反,保留更多段可以加速索引,因为合并发生的频率较低,更新不太可能触发合并。但搜索在计算上会变得更加昂贵,并且可能会更慢,因为必须在更多索引段中查找搜索词。更快的索引更新还意味着更短的提交周转时间,这意味着更及时的搜索结果。

控制已删除文档的百分比

当文档被删除或更新时,文档会被标记为已删除,但直到该段合并后才会从索引中删除。使用默认的 TieredMergePolicy 时,有两个参数可以调整,它们会影响索引中已删除文档的数量。

forceMergeDeletesPctAllowed

可选

默认值:10.0

当发出外部 expungeDeletes 命令时,任何已删除文档超过此百分比的段都将合并到一个新段中,并且与已删除文档关联的数据将被清除。0.0 的值将使 expungeDeletes 的行为与 optimize 基本相同。

deletesPctAllowed

可选

默认值:33.0

在正常段合并期间,尽最大努力确保索引中已删除文档的总百分比低于此阈值。有效设置在 20% 到 50% 之间。选择 33% 作为默认值,因为当此设置接近 20% 时,系统负载会大幅增加。

自定义合并策略

如果内置合并策略的配置选项不能完全满足你的用例,你可以通过创建自定义合并策略工厂(在配置中指定)或配置合并策略包装器(使用 wrapped.prefix 配置选项来控制它所包装的工厂将如何配置)来对其进行自定义

<mergePolicyFactory class="org.apache.solr.index.SortingMergePolicyFactory">
  <str name="sort">timestamp desc</str>
  <str name="wrapped.prefix">inner</str>
  <str name="inner.class">org.apache.solr.index.TieredMergePolicyFactory</str>
  <int name="inner.maxMergeAtOnce">10</int>
  <int name="inner.segmentsPerTier">10</int>
</mergePolicyFactory>

上面的示例显示了 Solr 的SortingMergePolicyFactory被配置为按"timestamp desc"对合并段中的文档进行排序,并包装在TieredMergePolicyFactory周围,该工厂配置为通过SortingMergePolicyFactorywrapped.prefix选项定义的inner前缀使用值maxMergeAtOnce=10segmentsPerTier=10。有关使用SortingMergePolicyFactory的更多信息,请参阅segmentTerminateEarly 参数

mergeScheduler

合并调度器控制合并如何执行。默认的ConcurrentMergeScheduler使用单独的线程在后台执行合并。备选方案SerialMergeScheduler不使用单独的线程执行合并。

ConcurrentMergeScheduler具有以下可配置属性。这些属性的默认值会根据底层磁盘驱动器是否为旋转磁盘而动态设置。有关更多详细信息,请参阅ConcurrentMergeScheduler 的动态默认值

maxMergeCount

可选

默认值:无

允许的最大同时合并数。如果需要合并,但我们已经运行了这么多线程,则索引线程将阻塞,直到合并线程完成。请注意,Solr 一次只会运行最小的maxThreadCount合并。

maxThreadCount

可选

默认值:无

应该同时运行的最大同时合并线程数。这必须小于maxMergeCount

ioThrottle

可选

默认值:无

布尔值(truefalse)用于显式控制 I/O 限制。默认情况下,启用限制,CMS 将在合并时限制 I/O 吞吐量,以便为其他(搜索、索引)留出一些空间。

示例:动态默认值
<mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler"/>
示例:显式默认值
<mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler">
  <int name="maxMergeCount">9</int>
  <int name="maxThreadCount">4</int>
</mergeScheduler>

mergedSegmentWarmer

在将 Solr 用于近实时用例时,可以在合并提交之前配置合并段预热器以预热新合并段上的读取器。这对于近实时搜索不是必需的,但将在合并完成后打开新的近实时读取器时减少搜索延迟。

<mergedSegmentWarmer class="org.apache.lucene.index.SimpleMergedSegmentWarmer"/>

复合文件段

每个 Lucene 段通常由十几或更多个文件组成。Solr 可配置为使用文件扩展名 .cfs(代表“复合文件段”)将 Lucene 段的所有文件捆绑到单个复合文件中。

CFS 段可能会因各种原因而导致轻微的性能下降,具体取决于运行时环境。例如,文件系统缓冲区通常与打开的文件描述符相关联,这可能会限制每个索引可用的总缓存空间。

在允许每个进程打开的文件数量有限的系统上,CFS 可以避免达到该限制。还可以使用 Linux/Unix ulimit 命令或其他操作系统的类似命令调整操作系统的打开文件限制。

CFS:新段与合并段

要配置是否应为新写入的段使用 CFS,请参见上面描述的 useCompoundFile 设置。要配置是否为合并段使用 CFS,请查看 mergePolicyFactory 的 Javadoc。

许多 合并策略 实现都支持 noCFSRatiomaxCFSSegmentSizeMB 设置,其默认值可防止将复合文件用于大段,但确实将复合文件用于小段。

段信息屏幕

管理 UI 中的段信息屏幕可让你查看此核心底层 Lucene 索引中各个段的可视化,其中包括每个段的大小信息(以字节和文档数表示)以及有关这些段的其他基本元数据。最明显的是已删除文档的数量,但你可以将鼠标悬停在段上以查看其他数字详细信息。

image

此信息可能对人们做出有关其数据最优 合并设置 的决策有所帮助。

索引锁

lockType

LockFactory 选项指定要使用的锁定实现。

有效的锁定类型选项集取决于你已配置的 DirectoryFactory

以下列出的值受 StandardDirectoryFactory(默认值)支持

  • native(默认)使用 NativeFSLockFactory 指定本机操作系统文件锁定。如果第二个 Solr 进程尝试访问该目录,它将失败。当多个 Solr Web 应用程序尝试共享单个索引时,请勿使用。另请参阅 NativeFSLockFactory javadoc

  • simple 使用 SimpleFSLockFactory 指定用于锁定的普通文件。另请参阅 SimpleFSLockFactory javadoc

  • single(专家)使用 SingleInstanceLockFactory。适用于只读索引目录的特殊情况,或者当不可能有多个进程尝试修改索引(即使是按顺序)时。此类型将防止同一 JVM 内的多个内核尝试访问同一索引。

    如果不同 JVM 中的多个 Solr 实例修改索引,此类型不会防止索引损坏。
  • hdfs 使用 HdfsLockFactory 支持将索引和事务日志文件读写到 HDFS 文件系统。有关使用此功能的更多详细信息,请参阅 Solr on HDFS 部分。

<lockType>native</lockType>

writeLockTimeout

等待 IndexWriter 上的写锁定的最长时间。默认值为 1000,以毫秒为单位。

<writeLockTimeout>1000</writeLockTimeout>

其他索引设置

还有一些其他参数可能对您的实现配置很重要。这些设置会影响对索引进行更新的方式或时间。

deletionPolicy

控制在回滚的情况下如何保留提交。默认值为 SolrDeletionPolicy,它采用以下参数

maxCommitsToKeep

可选

默认值:无

要保留的最大提交数。

maxOptimizedCommitsToKeep

可选

默认值:无

要保留的最大优化提交数。

maxCommitAge

可选

默认值:无

要保留的任何提交的最大年龄。这支持 DateMathParser 语法。

<deletionPolicy class="solr.SolrDeletionPolicy">
  <str name="maxCommitsToKeep">1</str>
  <str name="maxOptimizedCommitsToKeep">0</str>
  <str name="maxCommitAge">1DAY</str>
</deletionPolicy>

infoStream

InfoStream 设置指示底层 Lucene 类将索引过程中的详细调试信息作为 Solr 日志消息写入。请注意,启用此功能可能会大幅增加日志大小,并且可能导致高流量系统中出现一些性能延迟。默认值为 false

<infoStream>false</infoStream>