Lucene-MergePolicy详解

news2024/11/25 4:26:34

简介


该文章基于业务需求背景,因场景需求进行参数调优,下文会尽可能针对段合并策略(SegmentMergePolicy)的全参数进行说明。

主要介绍TieredMergePolicy,它是Lucene4以后的默认段的合并策略,之前采用的合并策略为LogMergePolicy,建议自行熟悉LogMergePolicy后再了解TieredMergePolicy,这样对于两种段合并策略的优缺点就一目了然,后续即可根据不同业务使用对应的策略,下面对两种策略的差异做一个简单总结:

  1. LogMergePolicy总是合并相邻的段文件,合并相邻的段文件(Adjacent Segment)描述的是对于IndexWriter提供的段集,LogMergePolicy会选取连续的部分(或全部)段集区间来生成一个待合并段集;
  2. TieredMergePolicy中会先对IndexWriter提供的段集进行排序,然后在排序后的段集中选取部分(可能不连续)段来生成一个待合并段集,即非相邻的段文件(Non-adjacent Segment)。

一句话描述:TieredMergePolicy:找出大小接近且最优的段集。下面对该概括进行详细分析。频繁且大量的段合并会造成进程CPU飙升。

TieredMergePolicy


TieredMergePolicy的一些参数


合并类型(MERGE_TYPE)


MERGE_TYPE中描述了IndexWriter在不同状态下调用合并策略的三种类型:

  • NATURAL:IndexWriter对缩影执行变更操作后调用合并策略;
  • FORCE_MERGE:IndexWriter需要需要将索引中包含所有的段集数量(total set of segments in the index)合并为指定数量;
  • FORCE_MERGE_DELETES:IndexWriter需要将索引中包含所有的段中的被删除文件进行抹去(expunge)操作。

三中类型触发过程处理逻辑一致,下文仅对NATURAL进行介绍。

maxMergeAtOnce(可配置)

maxMergeAtOnce的缺省值为10,描述了在NATURAL类型下执行一次合并操作最多包含的段的个数(Maximum number of segments to be merged at a time during "normal" mergin)。

segsPerTier(可配置)

segsPerTier的默认值为10,描述了每一层(层级的概念类似LogMergePolicy,这里不做赘述)中需要包含segsPerTier个段才允许合并,例外情况就是当段集中包含的被删除的文档数量达到某个值(下文会介绍),就不用考虑segsPerTier中的段的个数。

mergeFactor

mergeFactor描述了执行一次合并操作最多包含的段的个数,该值计算方式如下:

final int mergeFactor = (int) Math.min(maxMergeAtOnce, segsPerTier);

段大小(SegmentSize)


SegmentSize描述了一个段的大小,他是该段中除去被删除文档的索引信息的所有索引文件的大小的综合。

maxMergedSegmentBytes(可配置)

maxMergedSegmentBytes缺省值为5G,它有两个用途:

  1. 限制合并段集大小总量:待合并的段集大小总和不能超过该值;
  2. 限制大段(Segment with huge size)合并:该值的一半,即(maxMergedSegmentBytes / 2.0)用来描述某个段如果大小超过就不参与合并(限制大段还要同时满足被删除文档的条件,在下文会介绍)

另外值得一提的是,该值为内存杀手。内存有限的情况下,该值为必配项(5G的merge行为,在非受控堆外,将内存撑满)如下pmap图可见一般:

hitTooLarge

hitTooLarge是一个布尔值,当OneMerge中所有段的大小总和接近maxMergedSegmentBytes,hitTooLarge会被置为true,该值影响OneMerge的打分。

deletesPctAllowed(可配置)

deletesPctAllowed的默认值为33(百分比),自定义该值时允许的值域为[20,50],该值有两个用途:

  1. 限制大段合并:需要满足该段的SegmentSize≥(maxMergedSegmentBytes/2.0);并且满足段集中的被删除文档的索引信息大小占总索引文件大小的比例totalDelPct≤deletedPctAllowed或该段中被删除文档的索引信息大小占段中索引文件大小的比例segDelPct≤deletesPctAllowed,如下判断逻辑:
    (SegmentSize > (maxMergedSegmentBytes / 2)) && (totalDelPct <= deletesPctAllowed || segDelPct <= deletesPctAllowed)
  2. 计算allowedDelCount:计算公式如下,其中totalMaxDoc描述了段集中除去被删除文档的文档数量总和,allowedDelCount的介绍见下文:
    int allowedDelCount = (int) (deletesPctAllowed * totalMaxDoc / 100);
allowedSegCount、allowedDelCount
  • allowedSegCount:该值描述了段集内每个段的大小SegmentSize是否比较接近(segments of approximately equal size),根据当前索引大小来估算当前索引中"应该"有多少个段,如果实际的段个数小于估算值,那么说明索引中的段不满足差不多都相同(approximately equal size),那么就不会选出OneMerge(这里不赘述该名词含义,见LogMergePolicy)。allowedSegCount的最小值为segsPerTier,allowedSegCount的值越大,索引中会堆积更多的段,说明IndexWriter提交的段集(不包含大段)中最大的段的MaxSegmentSize跟最小的段MinSegmentSize相差越大,或者最小的段MinSegmentSize占段集总大小totalSegmentSize的占比特别低,一个原因在于有些flush()或者commit()的文档数相差太大,另一个原因是可配置参数floorSegmentBytes值设置的太小。
  • allowedDelCount:描述了IndexWriter提交的段集(不包含大段)中包含的被删除文档数量,在NATURAL类型下,当某个段集中的成员个数不满足allowedSegCount时,但是如果该段集(不包含大段)中包含的被删除的文档数量大于allowedDelCount,那么该段集还可以继续参与剩余的合并策略的处理(因为执行段的合并的一个非常重要的目的就是"干掉"被删除的文档号),否则就该段集此次不生成一个oneMerge。
floorSegmentBytes(可配置,重要!!!)

floorSegmentBytes缺省值为2MB(2 * 1024 * 1024),该值描述了段的大小segmentSize小于floorSegmentBytes的段,他们的segmentSize都当做floorSegmentBytes。

(源码原文:Segments smaller than this are "rounded up" to this size, ie treated as equal (floor) size for merge selection)
使计算出来的allowedSegCount较小,这样能尽快的将小段(tiny Segment)合并,另外该值还会影响OneMerge的打分(下文会介绍)。

设置了不合适的floorSegmentBytes后会发生以下的问题:

  • floorSegmentBytes的值太小:导致allowedSegCount很大(allowedSegCount=n*segsPerTier+m 0≤m≤segsPerTier , n≥1),特别是段集中最小的段MinSegmentSize占段集总大小totalSegmentSize的占比特别低,最终使得索引中一段时间存在大量的小段,因为段集的总数小于等于allowedSegCount是不会参与段合并的(如果不满足allowedDelCount的条件)。源码中解释floorSegmentBytes的用途的原文为: This is to prevent frequent flushing of tiny segments from allowing a long tail in the index;
  • floorSegmentBytes的值太大:导致allowedSegCount很小(最小值为segsPerTier),即较大的段合并可能更频繁,段越大,合并开销(合并时间,线程频繁占用)越大(在后面的文章中会介绍索引文件的合并)。

SegmentSize多小为小段(tiny Segment),这个定义取决于不同的业务,如果某个业务中认为小于TinySegmentSize的段都为小段,那么floorSegmentBytes的值大于TinySegmentSize即可。

段合并流程图


详细处理逻辑可以通过阅读Lucene源码得到(org.apache.lucene.index.TieredMergePolicy#findMerges),如下代码段为入口:

public MergeSpecification findMerges(MergeTrigger mergeTrigger, SegmentInfos infos, MergeContext mergeContext) throws IOException {
  final Set<SegmentCommitInfo> merging = mergeContext.getMergingSegments();
  // Compute total index bytes & print details about the index
  long totIndexBytes = 0;
  long minSegmentBytes = Long.MAX_VALUE;
  
  int totalDelDocs = 0;
  int totalMaxDoc = 0;
  
  long mergingBytes = 0;

  List<SegmentSizeAndDocs> sortedInfos = getSortedBySegmentSize(infos, mergeContext);
  Iterator<SegmentSizeAndDocs> iter = sortedInfos.iterator();
  while (iter.hasNext()) {
    SegmentSizeAndDocs segSizeDocs = iter.next();
    final long segBytes = segSizeDocs.sizeInBytes;
    if (verbose(mergeContext)) {
      String extra = merging.contains(segSizeDocs.segInfo) ? " [merging]" : "";
      if (segBytes >= maxMergedSegmentBytes) {
        extra += " [skip: too large]";
      } else if (segBytes < floorSegmentBytes) {
        extra += " [floored]";
      }
      message("  seg=" + segString(mergeContext, Collections.singleton(segSizeDocs.segInfo)) + " size=" + String.format(Locale.ROOT, "%.3f", segBytes / 1024 / 1024.) + " MB" + extra, mergeContext);
    }
    if (merging.contains(segSizeDocs.segInfo)) {
      mergingBytes += segSizeDocs.sizeInBytes;
      iter.remove();
      // if this segment is merging, then its deletes are being reclaimed already.
      // only count live docs in the total max doc
      totalMaxDoc += segSizeDocs.maxDoc - segSizeDocs.delCount;
    } else {
      totalDelDocs += segSizeDocs.delCount;
      totalMaxDoc += segSizeDocs.maxDoc;
    }

    minSegmentBytes = Math.min(segBytes, minSegmentBytes);
    totIndexBytes += segBytes;
  }
  assert totalMaxDoc >= 0;
  assert totalDelDocs >= 0;

  final double totalDelPct = 100 * (double) totalDelDocs / totalMaxDoc;
  int allowedDelCount = (int) (deletesPctAllowed * totalMaxDoc / 100);

  // If we have too-large segments, grace them out of the maximum segment count
  // If we're above certain thresholds of deleted docs, we can merge very large segments.
  int tooBigCount = 0;
  iter = sortedInfos.iterator();

  // remove large segments from consideration under two conditions.
  // 1> Overall percent deleted docs relatively small and this segment is larger than 50% maxSegSize
  // 2> overall percent deleted docs large and this segment is large and has few deleted docs

  while (iter.hasNext()) {
    SegmentSizeAndDocs segSizeDocs = iter.next();
    double segDelPct = 100 * (double) segSizeDocs.delCount / (double) segSizeDocs.maxDoc;
    if (segSizeDocs.sizeInBytes > maxMergedSegmentBytes / 2 && (totalDelPct <= deletesPctAllowed || segDelPct <= deletesPctAllowed)) {
      iter.remove();
      tooBigCount++; // Just for reporting purposes.
      totIndexBytes -= segSizeDocs.sizeInBytes;
      allowedDelCount -= segSizeDocs.delCount;
    }
  }
  allowedDelCount = Math.max(0, allowedDelCount);

  final int mergeFactor = (int) Math.min(maxMergeAtOnce, segsPerTier);
  // Compute max allowed segments in the index
  long levelSize = Math.max(minSegmentBytes, floorSegmentBytes);
  long bytesLeft = totIndexBytes;
  double allowedSegCount = 0;
  while (true) {
    final double segCountLevel = bytesLeft / (double) levelSize;
    if (segCountLevel < segsPerTier || levelSize == maxMergedSegmentBytes) {
      allowedSegCount += Math.ceil(segCountLevel);
      break;
    }
    allowedSegCount += segsPerTier;
    bytesLeft -= segsPerTier * levelSize;
    levelSize = Math.min(maxMergedSegmentBytes, levelSize * mergeFactor);
  }
  // allowedSegCount may occasionally be less than segsPerTier
  // if segment sizes are below the floor size
  allowedSegCount = Math.max(allowedSegCount, segsPerTier);

  if (verbose(mergeContext) && tooBigCount > 0) {
    message("  allowedSegmentCount=" + allowedSegCount + " vs count=" + infos.size() +
        " (eligible count=" + sortedInfos.size() + ") tooBigCount= " + tooBigCount, mergeContext);
  }
  return doFindMerges(sortedInfos, maxMergedSegmentBytes, mergeFactor, (int) allowedSegCount, allowedDelCount, MERGE_TYPE.NATURAL,
      mergeContext, mergingBytes >= maxMergedSegmentBytes);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1048689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络时钟程序Net_Clock

网络时钟程序Net_Clock 小程序的源代码,着重编程思想,巧妙的构思架构... 主要功能:简单的Socket网络套接从时间服务器获取时间,timeSetEvent精度定时器,颜色方案,自绘标题栏,自绘菜单...等等 VS2015平台的精度时钟程序,北京,美东,美中三个时区日期时间显示,多种颜色方案显示…

深入理解常见应用级算法思想

1 概论 1.1 概念 1.1.1 数据结构 1&#xff09;概述 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。 2&#xff09;划分 从关注的维度…

洗文案神器,不同洗文案神器怎么选择

在数字时代&#xff0c;文字的重要性变得愈发突出&#xff0c;不论是在商业领域的广告宣传、自媒体的文章创作&#xff0c;还是学术界的研究论文&#xff0c;文字都是传递信息和思想的关键媒介。然而&#xff0c;创作高质量的文案并非易事&#xff0c;这就是为什么越来越多的人…

FFmpeg安装教程

一、下载安装 打开官方网站&#xff0c;ffmpeg管网地址&#xff0c;点击左侧download或页面中的绿色Download按钮。 选择要下载的平台&#xff0c;windows版本选择红框第一个&#xff0c;第二个是github平台 点击左侧release builds&#xff0c;选择要下载的软件版本&#x…

【STM32】sct 分散加载文件的格式与应用

简介 当工程按默认配置构建时&#xff0c;MDK 会根据我们选择的芯片型号&#xff0c;获知芯片的内部FLASH 及内部 SRAM 存储器概况&#xff0c;自动生成一个以工程名命名的后缀为*.sct 的分散加载文件(Linker Control File&#xff0c;scatter loading)&#xff0c;链接器根据…

巨人互动|Google海外户Google SEO工作为何要把控细节

Google SEO&#xff08;搜索引擎优化&#xff09;是一项为了提高网站在Google搜索结果中的排名和可见性的策略和技术。在进行SEO工作时&#xff0c;把控细节非常重要&#xff0c;本文小编讲讲关于为何要把控细节的原因。 巨人互动|Google海外户&Google内容定位介绍&#xf…

当当网商品详情数据接口

当当网商品详情数据接口可以通过当当网的开放平台获取相关信息。您可以注册当当开放平台账号&#xff0c;并按照要求提交申请获取API接口的调用凭证。获得授权后&#xff0c;您将会收到一组AccessKey和SecretKey。使用编程语言&#xff08;如Java&#xff09;调用API接口&#…

聊一聊JDK21-虚拟线程

目录 前言 Virtual Threads的开始 为什么需要Virtual Threads JDK19 预览版初次出现 JDK21 Virtual Threads的正式发布 Virtual Threads 该怎么使用 简单聊聊Virtual Threads的实现 使用时候的注意事项 本地尝鲜一下JDK21及Virtual Threads 结语 前言 2023年9月19日…

26272-2010 地面数字电视调谐器基本性能要求和测量方法.

声明 本文是学习GB-T 26272-2010 地面数字电视调谐器基本性能要求和测量方法. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了地面数字电视接收设备用特高频/超高频(VHF/UHF) 电子式调谐器基本性能要求 和测量方法。 本标准适用…

数据结构与算法(C语言版)P8---树、二叉树、森林

【本节目标】 树概念及结构。二叉树概念及结构。二叉树常见OJ题练习。 1、树概念及结构 1.1、树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一颗倒挂的树&#xf…

再看dockerfile指令用法:80分钟一口气学完docker+k8s!带你掌握docker+k8s所有核心知识点,全程干货,无废话!

dockerfile实践 需求&#xff1a;通过dockerfile&#xff0c;构建nginx镜像&#xff0c;且容器运行后&#xff0c;生成的页面显示“书季&#xff0c;要攒劲哦~” #1、穿件dockerfile,注意文件名必须是这个。 [rootHadoop2 learn_docker]# cat dockerfile FROM nginx RUN echo…

linux opensuse使用mtk烧录工具flashtool

环境 linux发行版&#xff1a;opensuse leap 15.5 工具&#xff1a;SP_Flash_Tool_Selector_exe_Linux_v1.2316.00.100.rar 或其他版本 目标&#xff1a;mtk设备 下载链接 https://download.csdn.net/download/zmlovelx/88382784 或网络搜索。 使用 opensuse可直接解压后使…

HOMER7配置告警

概述 HOMER是一款100%开源的针对SIP/VOIP/RTC的抓包工具和监控工具。 HOMER是一款强大的、运营商级、可扩展的数据包和事件捕获系统&#xff0c;是基于HEP/EEP协议的VoIP/RTC监控应用程序&#xff0c;并可以使用即时搜索、处理和存储大量的信令、RTC事件、日志和统计信息。 …

【数据仓库设计基础(二)】维度数据模型

文章目录 一. 概述二. 维度数据模型建模过程三. 维度规范化四. 维度数据模型的特点五. 维度数据模型1. 星型模式1.1&#xff0e;事实表1.2&#xff0e;维度表1.3&#xff0e;优点1.4&#xff0e;缺点1.5&#xff0e;示例 2. 雪花模式2.1&#xff0e;数据规范化与存储2.2&#x…

PreMaint设备管理系统:实现制药企业的CSV合规性

在当今数字化时代&#xff0c;制药企业越来越依赖计算机化系统来支持其各个方面的运营&#xff0c;从研发到生产再到质量控制。然而&#xff0c;这些系统的使用不仅需要高效性和可靠性&#xff0c;还需要符合法规要求&#xff0c;尤其是药品生产质量管理规范&#xff08;Good M…

新零售革命:可视化助力零售业焕发新生

一、什么是新零售&#xff1f; 新零售是一种融合了传统零售业和数字科技的商业模式&#xff0c;旨在提升零售业的效率、便捷性和个性化。它将线上和线下的零售渠道结合在一起&#xff0c;通过数字技术、大数据分析、人工智能等手段&#xff0c;实现了以下几个主要特征和目标&a…

图像语义分割 FCN图像分割网络详解

图像语义分割 FCN图像分割网络详解 0、介绍1、VGG16网络结构2、转置卷积3、FCN-32S、FCN-16S&#xff0c;FCN-8S网络结构4、损失函数5、膨胀卷积6、FCN(Backbone-ResNet-50)6.1 项目框架6.2 ResNet50网络结构6.3 FCN(Backbone-ResNet-50)网络结构6.4 FCN(Backbone-ResNet-50)模…

基于SpringBoot的大学生就业招聘系统的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 求职信息管理 首页 招聘信息管理 岗位申请管理 岗位分类 企业管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网信息的飞速发展&#xff0c;大学生就业成为一个难题&#xff0c;好多公司都舍不…

【RV1103】Luckfox Pico RV1103 开发记录

文章目录 对比uboot的差别Linux的差别其他差别编译命令对比板级配置选择spi-nand flashemmc/SD 卡spinand flash烧录差别由于没有原理图--引脚分析 对比 linux defconfiglinux dtsuboot defconfiguboot fragmentluckfox-picosd/tf (emmc)luckfox_rv1106_linux_defconfigrv1103…

澳大利亚海运价格下半年走势

随着全球疫情的逐渐缓解&#xff0c;国际贸易开始逐步恢复。在这个过程中&#xff0c;澳大利亚作为全球重要的贸易伙伴&#xff0c;其海运价格也成为了市场关注的焦点。本文将从下半年的市场预期、影响因素以及行业动态等方面&#xff0c;对澳大利亚海运价格走势进行分析展望。…