Roaring位图使用的存储空间比普通位集更多。

4

我有一个位集合(bitset),用来跟踪物品是否存在,例如:

b = 01100110000

它代表第二个和第三个物品存在,而第一个和第四个物品不存在。

在寻找能够优化这个位集合数组的库时,我发现了非常令人兴奋的Roaring bitmaps

我做了一个快速测试:

    public static void main(String[] args) throws IOException {
        RoaringBitmap roaringBitMap = new RoaringBitmap();
        BitSet bitSet = new BitSet(5000);
        double prob = 0.001;
        Random random = new Random();
        for (int i = 0; i < 5000; i++) {
            if (random.nextDouble() < prob) {
                bitSet.set(i);
                roaringBitMap.add(i);
            }
        }
        System.out.println(bitSet.cardinality());
        System.out.println("bitset bytes: "+ bitSet.size());
        System.out.println("RoaringBitmap bytes: " + roaringBitMap.getSizeInBytes() * 8);
    }

基本上我们设置了一些值并检查数据结构的总大小。

当我们使用多个prob值运行时,我得到了:

prob byte bitset bytes RoaringBitmap bytes
0.001 5056 288
0.01 5056 944
0.1 5056 7872
0.999 5056 65616

如果您观察到随着插入更多数字,RoaringBitmap的内存占用增加。

  1. 这是预期的吗?
  2. 在最坏的情况下,它不应该只回退到基于位集的实现吗?
  3. 不能将0.999视为0.001的反向,并将其存储在288个字节中吗?
  4. 在进行服务间调用并使用jackson库(但不是基于字节的序列化库)时,表示这些位集的字符串的最优方式是什么?

这个 api文档 实际上描述了内存占用情况。 - g00se
我确实读过那篇文章,但是如果你仔细思考的话,你可以将最坏情况限制在位集合加上一些元数据开销之内。我们为什么要超出位集合这么多呢?这是我的问题。 - best wishes
不确定 add 到底在做什么。它 可能 像调用 StringBuilder.append 一样,其中存储分配跳跃的因子不是一。似乎没有 RoaringBitmap 可以为有限数量的字节创建位图。至于 String 的事情,提醒您,对于我来说,BitSet 的每个位的可视化压缩到 69 字节。 - g00se
3个回答

3

当条目数量较少时,似乎会出现这种情况,但随着条目数量的增加,差异变得不那么明显。虽然库作者没有确认(我在这里提问并在这里跟进了),但是保留HTML标记。

概率 条目数 位图位数 RoaringBitmap位数 节约%
0.001 50000 50048 928 98
0.01 50000 50048 7744 84
0.1 50000 50048 65616 -31
0.999 50000 50048 65616 <- 注意它不会增加 -31
0.001 500000 500032 8704 98
0.01 500000 500032 80720 83
0.1 500000 500032 524480 -4
0.999 500000 500032 524480 <- 注意它不会增加 -4
0.001 50000000 50000000 835232 98
0.01 50000000 50000000 8036368 83
0.1 50000000 50000000 50016240 -0.03
0.999 50000000 50000000 50016240 <- 注意它不会增加 -0.03

看起来,随着条目数量的增加,它们可能只在场景后面使用位图。结论是不要盲目使用库,要根据您的用例进行测试。


这是预期的。一旦您拥有足够密度的数据,Roaring Bitmap 就会回退到 Bitmap,因此您的总内存使用量只会比 Bitmap 稍微大一点。 - user179156

2
Roaring Bitmap格式有公开的规范:https://github.com/RoaringBitmap/RoaringFormatSpec。内存使用只是应用程序性能中的一个因素。Roaring位图旨在提供经济的存储,同时在实际应用中提供高性能。给定N个属于[0,x)的整数,则Roaring位图的序列化大小(以字节为单位)不应超过以下限制:8 + 9 * ((long)x+65535)/65536 + 2 * N。也就是说,对于固定的宇宙大小(x),Roaring位图永远不会每个整数使用超过2个字节。没有一种数据结构是始终理想的。您应该确保Roaring位图适合您的应用程序配置文件。至少有两种情况下,Roaring位图可以很容易地被优秀的压缩替代品所取代:1. 您拥有跨越大间隔的少量随机值(即,您拥有非常稀疏的集合)。例如,取集合0、65536、131072、196608、262144…如果这是您的应用程序的典型情况,则可以考虑使用哈希集或简单的排序数组。2. 您具有随机值的密集集合,这些值从不形成连续的值序列。例如,考虑集合0,2,4,...,10000。如果这是您的应用程序的典型情况,则使用传统的位集可能更好。相关Roaring参考资料。
  • 丹尼尔·勒米尔(Daniel Lemire)、欧文·卡瑟(Owen Kaser)、纳森·库尔兹(Nathan Kurz)、卢卡·德里(Luca Deri)、克里斯·奥哈拉(Chris O'Hara)、弗朗索瓦·圣雅克(François Saint-Jacques)、格雷戈里·西-扬凯(Gregory Ssi-Yan-Kai),Roaring Bitmaps: Implementation of an Optimized Software Library,《软件:实践与经验》2018年4月第48卷第4期,867-895页。
  • 萨米·尚比(Samy Chambi)、丹尼尔·勒米尔、欧文·卡瑟、罗伯特·戈丁(Robert Godin),Better bitmap performance with Roaring bitmaps, 《软件:实践与经验》2016年5月第46卷第5期,709-719页。
  • 丹尼尔·勒米尔、格雷戈里·西-扬凯、欧文·卡瑟,Consistently faster and smaller compressed bitmaps with Roaring, 《软件:实践与经验》2016年11月第46卷第11期,1547-1569页。
  • 萨米·尚比、丹尼尔·勒米尔、罗伯特·戈丁、卡梅尔·布克哈法(Kamel Boukhalfa)、查尔斯·艾伦(Charles Allen)、方劲仁(Fangjin Yang),Optimizing Druid with Roaring bitmaps,IDEAS 2016, 2016年。

0

RoaringBitmap有三种容器类型,在我们的场景中,我们主要使用BitmapContainer。每个BitmapContainer可以存储65535个元素,占用8k内存。然而,存储是根据高16位和低16位进行分割的。基于高16位选择相应的桶。如果相应的桶不存在(元素范围差异为65535),它将被存储在新的桶中。在数据过于稀疏的情况下,这可能导致许多未填满的桶,从而导致一些冗余内存。这可能会导致RoaringBitmap在某些情况下使用比常规位图更多的内存。如果稀疏数据的范围差异为65535或元素数量较少,则使用的内存比位图少。它最大的优点是不需要根据最大偏移量分配空间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接