如何为大数据创建高效的位集结构?
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
【讨论】:
以上是关于如何为大数据创建高效的位集结构?的主要内容,如果未能解决你的问题,请参考以下文章