索引压缩算法New PForDelta简介以及使用SIMD技术的优化

本文涉及的产品
推荐全链路深度定制开发平台,高级版 1个月
简介: New PForDelta算法介绍 倒排索引的数据包括docid, term frequency, term position等,往往会占用很大的磁盘空间,需要进行压缩。压缩算法需要考虑两点:压缩效果和解压缩效率。

2000元阿里云代金券免费领取,2核4G云服务器仅664元/3年,新老用户都有优惠,立即抢购>>>


阿里云采购季(云主机223元/3年)活动入口:请点击进入>>>,


阿里云学生服务器(9.5元/月)购买入口:请点击进入>>>,

written by 普队

New PForDelta算法介绍

倒排索引的数据包括docid, term frequency, term position等,往往会占用很大的磁盘空间,需要进行压缩。压缩算法需要考虑两点:压缩效果和解压缩效率。一般来说,提升解压缩效率,减少用户查询的响应时间更加重要。PForDelta算法以及它的改进版本New PForDelta算法在拥有不错压缩率的情况下解压缩性能也十分优秀。

PForDelta算法

算法的第一步是要进行Delta Encoding操作,对于一组按照顺序从小到大排列的数据,不需要保存每个元素的值,只需要保存相邻元素的差值即可。例如存储docid时就需要这么做,而对于不是递增排列的TF和TP,则没有这个操作,此时仅被称为PFor算法。

完成Delta Encoding后得到的数据会被拆分成多个block,每个block存储固定个数的数据(例如128个),算法会分别对每个block独立的压缩和解压。这样做除了可以利用数据的局部性特征,对不同部分采用不同的压缩策略外,还可以在解压缩时只选择解压部分block,不需要针对整个文件,例如查询某一term的position时只解压其所在block。

PForDelta算法的基础思想是对于一个block,认为其中大部分数据只需要较小的空间就可以存储下来,而剩下的部分被当做异常数据处理。一般通过设定一个值framebit,使得超过90%的数据都可以直接由framebit位存储下来,称为正常部分,剩下的小于10%的数据单独存储,称为异常部分。

比如一组数据如下:10, 34, 69, 77, 126, 137, 150, 179, 278, 279, ……..,在Delta Encoding后得到数据10, 24, 35, 8, 49, 11, 13, 29, 99, 1, …….,设定framebit = 5,那么小于32的数据都可以直接存下,大于等于32的有35, 49, 99需要单独存储。使用PForDelta压缩后的数据如下图所示:

11

图中第一个位置的“2”表示与第一个异常值的位置是2,往后数间隔2个可以找到第一个异常值的位置,可以通过异常部分知道这个异常值是35,然后根据这个位置的“1”又可以往后数间隔1个找到下一个异常值的位置,这个异常值是49,以此类推可以继续找下去。异常部分的存储是倒序的,这样做是为了在解压缩的时候更方便的把异常值填进去。

解压的过程就是先把正常部分每5位提取出来,然后按前面所说将异常值的位置找出来并且根据异常部分填入异常值。

除了存储数据外,整个数据还需要一个头信息,用于记录framebit的取值以及压缩后的长度等。

PForDelta算法会存在一个问题:异常数据的间隔可能超过framebit位能存储的最大值,例如framebit=5时异常值的间隔超过了31。一个可行的解决方法是将某些原来不是异常值的数据当成异常值处理,从而减小异常值的间隔,但是这样也造成了不必要的浪费。

New PForDelta算法

针对上面提到的问题,改进后的PForDelta算法的思路是:以128个数据为block大小时,异常值的间隔不会很大,可以把它们单独拿出来存储,而原来存储这些间隔大小的位置就用来存储异常值的低位,异常值的高位则和间隔一起存储在异常部分。

继续以上面Delta Encoding后的数据为例:10, 24, 35, 8, 49, 11, 13, 29, 99, 1, …….,设定framebit = 5。使用New PForDelta后的数据如下图所示:

22

可以比较与普通PForDelta的不同:正常部分开头存储的第一个异常值的位置没有了;圆圈内原来存储的是异常值的间隔,现在变成了35, 49, 99二进制形式下的低5位;异常部分存储的是第一个异常值35的位置“2”以及它除去低5位后的高位,异常值49与上一个异常值的间隔“1”以及它的高位,异常值99与上一个异常值的间隔“3”以及它的高位等等。

解压缩时首先将前面每5个bit存储的数据解压出来,然后处理异常部分:读到“2”,于是将“0000001”拼接到第2个位置“00011”之前得到35;读到“1”,将”00000001”拼接到第4个位置”10001”之前得到49;读到”3”,将“0000003”拼接到第8个位置”00011”之前得到99。(假设下标从0开始)

异常部分每个值的大小一般不会很大,可以用别的压缩算法继续压缩,例如indexlib中采用了s9算法(这里只是简单介绍一下):对每一个4字节32bit,选定一个提前规定的9种bit_length中的一种,例如选为7,且它对应的code_num为4,意思是接下来的4个数据都能用7bit的方式存储在这4个字节中,应当保证bit_length选的尽量小使得可以存储尽量多的数据。预先取定的9种bit_length保证它乘上对应的code_num不超过28,这样留下4bit的空间用于存储采用了第几种bit_length。

New PForDelta算法的优势与实现

算法的性能好坏与它的实现密切相关,原因是它的设计原则要求它CPU流水线友好,从而达到压缩率好的情况下解压效率也很优秀的目标。

因此实现时需要做到:对每个framebit分别实现函数;采用循环展开的优化方法;减少或避免分支结构出现。这些策略都是为了尽量保证流水线的通畅性。

使用SIMD技术

SIMD全称Single Instruction Multiple Data,单指令多数据流,通俗的说是指这样的指令集:收集多个操作数,将它们放入128位、256位甚至更多位的寄存器中(这个过程的访存操作也是并行的),同时(并行)对它们执行相同的操作。索引压缩算法看重压缩率和解压效率,New PForDelta算法解压时的指令序列契合SIMD技术对多个操作数执行相同操作的理念,因此可以使用SIMD技术来优化它。

New PForDelta算法解压时分为正常部分和异常部分的解压。异常部分需要将异常数据的高位依据间隔补到正常部分解压出来的数组中,不能使用SIMD指令,而正常部分只是将一系列按相同的framebit位存储的数据顺序提取到数组中,完全可以使用SIMD指令,因此我们只针对正常部分进行优化,优化的指令集是128位的sse4指令集(在编译时使用avx2编译选项,线上机器也支持avx2)。

来看一个简单的例子:framebit取8,解压时原来的实现方法是将一个int(4字节)中每8位用位运算取出分到数组中,解压16个数据则需要对4个int执行上述操作,采用sse4指令后只需将128位并行存入寄存器,然后并行的将它们分到数组的16个单元中。可以发现优化后的指令条数相比原来少了很多,但是流水线的流畅性就没有原来那么好了。另外,对于不规则的framebit(意思是有很多数据存储时横跨两个字节或者两个int),sse4指令需要添加一些额外的操作,超过原来解压方法所付出的代价。但是总体上来说,指令数目的减少弥补了流水线的问题,使用SIMD技术后解压效率有不错的提升,这将在后面介绍的测试效果中体现出来。

33

上图为原来解压的操作顺序,其中每个int的低位在左边。

44

上图为优化后解压的操作顺序,相同的标号代表并行执行。

测试效果

测试1

测试数据:没有异常值的随机数据

测试机器:CPU版本为v4的线上机器

蓝色和橙色:对应原始解压方法和新型解压方法

横坐标:表示用不同framebit压缩的数据(例如5表示此数据用framebit=5的方式压缩了)

纵坐标:表示解压速率,单位MB/s

55

测试2

测试数据:有接近10%异常值的随机数据

其它指标不变

66

可以发现,平均情况下解压速率提升了10%左右。framebit=6的异常是由于原先特别针对此情况采用了复杂的SIMD技术优化(汇编代码形式),framebit=15的异常原因主要是此种情况下sse指令特别复杂(每15位填充需要32个数据才能填满整int,因此需要很多额外的指令处理数据)。提升效果没有预想中的明显,可见New PForDelta算法流水线友好的设计初衷得到了体现。

结语

本文只讨论单纯使用SIMD技术对New PForDelta算法的提升作用,另一个优化思路是从索引结构上进行考虑,包括PForDelta和New PForDelta在不同场景下的对比、异常部分的压缩策略(例如是否采用s9)等。另外,压缩率和解压效率的平衡也是一个重要的课题。

目录
相关文章
|
1天前
|
机器学习/深度学习 自然语言处理 算法
深度学习算法简介(二)
深度学习算法简介(二)
|
1天前
|
算法 调度
基于CCG算法的IEEE33配电网两阶段鲁棒优化调度matlab
基于CCG算法的IEEE33配电网两阶段鲁棒优化调度matlab
|
5天前
|
人工智能 算法 测试技术
论文介绍:进化算法优化模型融合策略
【5月更文挑战第3天】《进化算法优化模型融合策略》论文提出使用进化算法自动化创建和优化大型语言模型,通过模型融合提升性能并减少资源消耗。实验显示,这种方法在多种基准测试中取得先进性能,尤其在无特定任务训练情况下仍能超越参数更多模型。同时,该技术成功应用于创建具有文化意识的日语视觉-语言模型。然而,模型融合可能产生逻辑不连贯响应和准确性问题,未来工作将聚焦于图像扩散模型、自动源模型选择及生成自我改进的模型群体。[论文链接: https://arxiv.org/pdf/2403.13187.pdf]
110 1
|
9天前
|
JavaScript 前端开发 算法
【JavaScript技术专栏】使用JavaScript实现常见算法
【4月更文挑战第30天】本文介绍了如何使用JavaScript实现常见算法,包括排序、搜索和图算法。首先,通过JavaScript的`sort`方法讨论了排序算法,以快速排序为例展示了自定义排序的实现。接着,探讨了二分查找这一高效的搜索算法,并提供了实现代码。最后,解释了深度优先搜索(DFS)图算法,并给出了在JavaScript中的实现。理解并运用这些算法能有效提升编程能力。
|
10天前
|
机器学习/深度学习 监控 算法
|
10天前
|
机器学习/深度学习 人工智能 算法
探索机器学习中的算法优化之路
【4月更文挑战第28天】 在机器学习的广阔天地中,算法是构建智能系统的核心。本文将深入探讨算法优化的策略与实践,从理论到应用,揭示提升模型性能的关键因素。我们将穿梭于参数调整、特征工程、模型选择和超参数优化等关键环节,剖析如何通过迭代改进,达到提高准确率、减少误差的目的。此文不仅为初学者提供启示,也为经验丰富的开发者提供深度思考,共同探索算法的极致潜能。
|
11天前
|
机器学习/深度学习 数据采集 算法
构建高效机器学习模型:从数据处理到算法优化
【4月更文挑战第28天】在数据驱动的时代,构建一个高效的机器学习模型是实现智能决策和预测的关键。本文将深入探讨如何通过精确的数据预处理、选择合适的学习算法以及进行细致的参数调优来提升模型的性能。我们将介绍一系列实用的技术和策略,包括特征工程、模型评估、超参数调整以及使用集成学习方法来增强模型的泛化能力。通过这些方法,读者将能够更好地理解并应用机器学习技术来解决实际问题。
|
11天前
|
机器学习/深度学习 自然语言处理 算法
深度解析深度学习中的优化算法:从梯度下降到自适应方法
【4月更文挑战第28天】 在深度学习模型训练的复杂数学迷宫中,优化算法是寻找最优权重配置的关键导航者。本文将深入探讨几种主流的优化策略,揭示它们如何引导模型收敛至损失函数的最小值。我们将比较经典的批量梯度下降(BGD)、随机梯度下降(SGD)以及动量概念的引入,进一步探索AdaGrad、RMSProp和Adam等自适应学习率方法的原理与实际应用。通过剖析这些算法的理论基础和性能表现,我们旨在为读者提供一个关于选择合适优化器的参考视角。
|
14天前
|
机器学习/深度学习 人工智能 算法
揭秘深度学习中的优化算法
【4月更文挑战第24天】 在深度学习的广阔天地中,优化算法扮演着至关重要的角色。本文将深入探讨几种主流的优化算法,包括梯度下降法、随机梯度下降法、Adam等,并分析它们的特点和适用场景。我们将通过理论分析和实例演示,揭示这些优化算法如何帮助模型更高效地学习参数,从而提高模型的性能。
|
15天前
|
人工智能 达摩院 算法
什么是优化技术?给算法小白同学的快速讲解和上手文
本文作者用一个曾经小白学习的视角,来讲解什么是优化问题,以及要如何用这个优化技术。
47768 1
http://www.vxiaotou.com