bitMap和roaringBitMap的了解

what:

  以一个“40亿个数据是4个字节的unsigned int 型的数据”为例。

  a、直接存储。(40 * 10^8) * 4byte = 14.9GB (1GB=2^10Mb=2^20kb=2^30byte);

  b、采用位图(bitmap)存储。40亿个数据都是位于[0, 2^32 - 1],每一位指的是一个bit位,而1byte(1字节)是8个bit,2^32bit = 2^29byte = 2^19kbyte=2^9Mb=512Mb

 

  如果数据很稀疏,例如:统计某个应用的用户数,用户id范围为[0, 2^32 - 1],如果只有几个用户在线时,还需要开辟512M的存储空间,那么浪费就大了。

  于是出现了“位图压缩的方式”,roaringBitMap就是其中一种。

 

  roaringbitmap属于是位图的一个进化,即压缩位图。在roaringbitmap中不只包含bitmap这一种数据结构,而是包涵了多种存储的方式,以此来达到压缩位图的目的。

 

Why:

  1、空间节省:bitmap比较适用于数据分布比较稠密的存储场景中;roarringBitMap稀疏存储上空间更省,稠密和bitMap一致;

  2、更高效的做交、并操作。

    a、逻辑结构节省计算量:将大块的bitmap分成各个小块,其中每个小块在需要存储数据的时候才会存在。所以当进行交集或并集运算的时候,只需要去计算存在的一些块,而不需要像bitmap那样对整个大的块进行计算。这里既不是用空间换时间,也没有用时间换空间,而是用逻辑的复杂度同时换取了空间和时间。

    b、逻辑结构优化程序:roaringbitmap维护了排好序的一级索引,以及有序的arraycontainer当进行交集操作的时候;计算时,根据需要在一级索引中找需要的内容。

 

 

 

 

How

  roaringBitMap采用分桶机制来实现节省空间。具体策略:

  1、首先,将 32bit int(无符号的)类型数据 划分为 2^16 个桶(即使用数据的前16位二进制作为桶的编号),每个桶有一个Container来存放一个数值的低16位。

  2、在存储和查询数值时,将数值 k 划分为高 16 位低 16 位,取高 16 位值找到对应的桶,然后在将低 16 位值存放在相应的 Container 中。

  注意:大家需要注意大桶里面的各个桶(container)是在需要的时候才会申请开辟

  以roaringBitMap存储31为例,其16进制为:0000001F,前16位为0000,后16为001F。

 

 

   

  roaringBigMap有四种小桶container:

    arraycontainer(数组容器),bitmapcontainer(位图容器),runcontainer(行程步长容器),sharedcontainer(共享容器):

 

  bitmapcontainer:

    位图,只不过这里位图的位数为2^16(65536)个,也就是2^16个bit,计算下来起所占内存就是8kb。然后每一位用0,1表示这个数不存在或者存在。如下图:

 

 

 

  arraycontainer:

    container默认使用arraycontainer(元素都是按从大到小的顺序排列的),由于container只有16位bit位,最大[0-65535),则用short int类型(占两个字节)即可。当ArrayContainer的容量超过4096(这里是指4096个short int即8k Byte)后,切换为bitmapcontainer(这个所占空间始终都是8k Byte,也就是16位bit)。即ArrayContainer存储稀疏数据,BitmapContainer存储稠密数据,可以最大限度地避免内存浪费。如下内存使用图:

 

 

  runcontainer:

    一种利用步长来压缩空间的方法。

    比如连续的整数序列 11, 12, 13, 14, 15, 27, 28, 29 会被 压缩为两个二元组 11, 4, 27, 2 表示:11后面紧跟着4个连续递增的值,27后面跟着2个连续递增的值,那么原先16个字节的空间,现在只需要8个字节,是不是节省了很多空间呢。不过这种容器不常用。

 

  sharedcontainer:

    它本身是不存储数据的,只是用它来指向arraycontainer,bitmapcontainer或runcontainer,就好比指针的作用一样。这个指针(sharedcontainer)可以被多个对象拥有,但是指针所指针的实质东西是被这多个对象所共享的。

    使用:进行roaringbitmap之间的拷贝的时候,有时并不需要将一个container拷贝多份。那么我们就可以使用sharedcontainer来指向实际的container,然后把sharedcontainer赋给多个roaringbitmap对象持有,这个roaringbitmap对象就可以根据sharedcontainer找到真正存储数据的container,这可以省去不必要的空间浪费。

 

posted @ 2022-04-25 11:07  修心而结网  阅读(2300)  评论(0编辑  收藏  举报