如何为大数据创建高效的位集结构?

Posted

技术标签:

【中文标题】如何为大数据创建高效的位集结构?【英文标题】:How to create efficient bit set structure for big data? 【发布时间】:2014-07-15 13:02:46 【问题描述】:

Java 的BitSet 在内存中,它没有压缩。

假设我在位图中有 10 亿个条目 - 内存中占用了 125 MB。 假设我必须对 10 个这样的位图进行 AND 和 OR 操作,它占用 1250 MB 或 1.3 GB 内存,这是不可接受的。 如何在不将它们未压缩在内存中的情况下对此类位图进行快速操作?

不知道bit-set中bit的分布情况。

我还查看了JavaEWAH,它是 Java BitSet 类的一个变体,使用运行长度编码 (RLE) 压缩。

有没有更好的解决方案?

【问题讨论】:

如果 AND 和 OR 只使用 2 个位图作为参数,为什么还要将 10 个位图保存在内存中? 把你的BitSet看成一组整数,它有多稀疏?也就是说,这个集合中存在多少个 BitSet 范围内的十亿个整数? 假设它们被缓存并在 10 个模块中使用。 @jean-loup Java BitSet 数据结构非常接近于均匀分布的位集的最优值。如果你想做得更好,你需要知道你的比特集是如何分布的。 在这种情况下,我的下一步将是测量和分析,以了解更多有关数据及其用途的信息。 【参考方案1】:

一种解决方案是让数组远离堆。

您需要阅读@PeterLawrey 撰写的this answer 以了解相关问题。

总的来说,Java 中的内存映射文件的性能非常好,它避免了在堆上保留大量对象。

操作系统可能会限制单个内存映射区域的大小。通过映射多个区域很容易解决这个限制。如果区域是固定大小的,则可以对实体索引进行简单的二进制操作,以在内存映射文件列表中找到对应的内存映射区域。

您确定需要压缩吗?压缩将以时间换空间。减少的 I/O 可能最终会节省您的时间,但也有可能不会。可以加 SSD 吗?

如果您还没有尝试过内存映射文件,请从它开始。我会仔细研究在 Peter's Chronicle 之上实现一些东西。

如果您需要更快的速度,可以尝试并行执行二进制操作。

如果您最终需要压缩,您总是可以在 Chronicle 的内存映射数组之上实现它。

【讨论】:

这正是我的建议。您想操作 1.3GB 数据但又不想占用这么多内存,然后使用内存映射文件,这将为您提供一个更小的窗口来查看文件中的数据。还可以使用并发线程通过 fork-join 或并行流并行执行操作。 内存映射文件是THE有效回答原始问题的最佳方式。我看到问题的措辞已经过编辑,以使压缩成为任何解决方案的必需部分。如果我知道如何对编辑进行否决,我会这样做。【参考方案2】:

从这里的 cmets 我要说的是对您最初问题的补充:

位域分布未知,因此BitSet 可能是我们可以使用的最佳选择 你必须在不同的模块中使用位域并且想要缓存它们

话虽如此,我的建议是实施专用缓存解决方案,如果 LRU 是可接受的驱逐策略,则使用带有访问顺序的 LinkedHashMap,并在磁盘上为BitSetS.

伪代码:

class BitSetHolder 

    class BitSetCache extends LinkedHashMap<Integer, Bitset> 
        BitSetCache() 
            LinkedHashMap(size, loadfactor, true); // access order ...
        

        protected boolean removeEldestEntry(Map.Entry eldest) 
            return size() > BitSetHolder.this.size; //size is knows in BitSetHolder
        
    
    BitSet get(int i)  // get from cache if not from disk
        if (bitSetCache.containsKey(i) 
             return bitSetCache.get(i);
        
        // if not in cache, put it in cache
        BitSet bitSet = readFromDisk();
        bitSetCache.put(i, bitSet);
        return bitSet();
    

这样:

您可以透明地访问 10 位集 您将最近访问的位集保存在内存中 您将内存限制为缓存的大小(如果您想创建一个组合 2 个其他位集的位集,则最小大小应为 3)

如果这是满足您要求的选项,我可以开发更多。无论如何,这适用于其他驱逐策略,LRU 是最简单的,因为它在 LinkedHashMap 中是原生的。

【讨论】:

【参考方案3】:

最佳解决方案在很大程度上取决于数据的使用模式和结构。

如果您的数据具有超出原始位 blob 的某些结构,则您可以使用不同的数据结构做得更好。例如,可以使用 DAG 在空间和查找时间上非常有效地表示单词列表。

Sample Directed Graph and Topological Sort Code

BitSet 在内部表示为 long[],这使得重构稍微困难一些。如果你从 openjdk 中获取源代码,你会想要重写它,以便在内部使用迭代器,由文件或内存中压缩 blob 支持。但是,您必须重写 BitSet 中的所有循环以使用迭代器,因此不必实例化整个 blob。

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/BitSet.java

【讨论】:

以上是关于如何为大数据创建高效的位集结构?的主要内容,如果未能解决你的问题,请参考以下文章

如何为项目构建高效的统一文件存储方案

如何为“大数据”分析项目设置架构?

DataSophon——国产开源大数据管理运维平台

如何为大数据处理构建高性能Hadoop集群

如何为大数据处理构建高性能Hadoop集群

如何为整个应用程序创建字体大小选项(小、正常、大)? [复制]