压缩算法:FOR算法和RBM算法

      倒排索引为什么需要压缩算法?对term(词项)其记录的倒排索引是

banana: 1,4
this: 1,2
apple: 2,3

  现在doc一共有10000行,term倒排索引可能就会变成banana: 1,2,3,4,78,90,1000,1001,1002,1003,9998,9999,实际存储就是一个个有序数组,直接存储的话就需要占用4byte * 12 = 48byte(1int占用4byte),有序数值数组是比较容易进行压缩处理的

FOR算法(Frame Of Reference)

  FOR算法核心思想是用减法来削减数值大小,达到降低空间存储。假设V(n)表示数组中第n个字段的值,经过FOR算法压缩的数值V(n)=V(n)-V(n-1)。存储的是后一位减去前一位的差值。存储是也不再按照int来计算,而是看这个数组的最大值需要占用多少bit来计算

  通过一个例子来体会:
  比如数组是73,300,302,332,343,372,原本需要4 * 6 byte = 24byte = 192bit
       压缩后:73,227,2,30,11,29
       数中227是最大的,需要8bit(227 < 2^8)来盛装,每个数值都不会超过8bit,需要的大小是6 * 8bit=48bit,把8bit的容器理解为一个箱子,总共需要6个箱子,所有箱子占48bit,但是这并不是我们的总大小,因为相比较于原数组,引入了一个箱子的概念,那么除了箱子数,还需要记录每个箱子的大小,需要有一个数来记录箱子大小,注意规定盛装大小不超过256bit,箱子大小值最大不超过2^8,即箱子大小值占用不超过8bit,因此总共的大小是48bit+8bit = 56bit

  看到压缩后大小由192bit降到56bit,已经有很大改善,但是这还不是FOR算法的终点,观察这组数中最大值227,后一位最小值是2,两者相差很大,2实际上只需要1bit来盛装,那么能不能进一步压缩呢?答案是可以,只是不再需要做差值,直接将数组分组,将其拆分为:

73,227
2,30,11,29

  占用空间就变成了73,227箱子大小8bit,2,30,11,29中最大30,箱子大小为5bit,数组总大小为16bit + 20bit = 36bit,不要忘记因为分成两组,要单独记录两组箱子大小值,总大小是36bit+2*8bit= 52bit
  是不是还可以进行压缩?是越小越好吗?还要考虑解码的问题,数据压缩后是要使用的,因此需要解码,压缩得越深,解码越耗时,因此不是越小越好,那么在哪里取一个平衡

RBM算法(RoaringBitMap)

   FOR算法核心是用减法来缩减数值大小,但是减法一定能缩减大小吗?但数值大小很大时,减法能够达到的效果是不明显的,比如100W,200W,300W,相减后是100W,100W,100W,依然很大,这时的压缩效果很不理想,所以引入了RBM算法

  RBM核心就是通过除法来缩减数值大小,但是并不是直接的相除。

  比如数组为1000,62101,131385,191173,196658
  其中196658的二进制表示为0000 0000 0000 0011 0000 0000 0011 0010,然后将其高16位和低16位分别转换为10进制:

  0000 0000 0000 0011 -> 3
  0000 0000 0011 0010 -> 50

  196658就转换成了(3,50)的表示形式,其效果就相当于除以2^16,商3余50

  因为商和余数都不超过16位,那么最大用16bit来存储足够,也就是short类型。因此商和余数都可以用一个short来盛装,那么所有的商就是一个short[],所有的余数就是一个short[][]
  将原数组除以2^16得:
  (0,1000),(0,62101),(2,313),(2,980),(2,60101),(3,50)
  转化为二维数组盛装
  0: 1000,62101
  2: 313,980,60101
  3: 50

  以下的二维数组,每一个Container中的数据当量足够多时我们认为他是有序连续的:
  0: 1000,62101
  2: 313,980,60101
  3: 50

  因此就可以使用bitmap来存储数据,按照规定一个Container的最大值是65534(这里为什么最大值是65534,思考一下,如果不明白往上看看原数组是怎么处理的),也就需要65535bit=8k的容器来存储,当然bitmap有个很明显的缺点,那就是无论Container中有多少个数,都要占用8k的大小,所以当数量不超过65535bit /16bit = 4096个时,使用short (16bit)来存储更划算,当每个Container的数量超过4096个时使用bitmap更加划算,那么使用bitmap的Container称为BitmapContainer

  综上Container有三种:ArrayContainer,BitmapContainer,RunContainer

  RBM算法的核心步骤如下:
    (1)数组中每个数除以2^16,以商,余数的形式表示出来
    (2)将相同商的归在一个Container,如果Contaniner中数值容量超过4096使用bitmap的形式来存储一个Container中的数,如果没有超过那就使用short[]来存储,如果是连续数组那就使用RunContainer来存储

 

 
  


  

posted on 2022-06-22 21:31  溪水静幽  阅读(452)  评论(0)    收藏  举报