首页 > 系统相关 >内存受限下找出亿级整数集合中的不重复元素

内存受限下找出亿级整数集合中的不重复元素

时间:2023-08-14 18:00:49浏览次数:43  
标签:元素 reader Filter 内存 受限 亿级 new Bloom

在大数据环境下,我们常常需要处理数量极其庞大的数据集,但由于内存大小的限制,无法直接加载到内存中进行操作。这时就需要设计适合内存受限环境的算法,来解决问题。本文将以在内存不足的情况下,找出亿级规模整数集合中的不重复元素为例,探讨一种基于Bloom Filter的数据结构的解决方案。

问题分析

假设有一个包含2.5亿个整数的集合,需要找出其中不重复的整数。但内存无法容纳全部的2.5亿个元素。如果直接对集合进行遍历,内存会溢出。

一个直观的想法是分批读取数据,每次处理一小部分,并用一个 HashSet 来计数。但随着处理的数据越来越多,HashSet 的大小也会越来越大,还是存在内存溢出的风险。

Bloom Filter解法

针对上述问题,我们可以考虑使用Bloom Filter这种空间效率极高的概率数据结构。

Bloom Filter本质是一个很长的二进制向量和一系列随机映射函数。对每个元素,通过映射函数将其映射到二进制向量的不同位,并将其置为1。查询时也通过相同的映射函数,查看相应位是否都是1。

利点是只需要一个二进制向量即可表示一个集合,不需要存储元素本身。并可以实现间隔查询,不需要对集合进行遍历。理论上,2.5亿个元素只需要225MB的Bloom Filter,远小于元素本身的内存占用。

具体地,思路是:

  1. 初始化一个225MB大小的Bloom Filter
  2. 分批读取整数数据,每次处理1万个
  3. 对每批数据,将元素存入Bloom Filter
  4. 再次遍历数据,检查每个元素是否在Bloom Filter中命中
  5. 未命中的元素即为不重复元素代码实现Java代码示例如下: java public static void findUniqueIntegers(String inputPath, String outputPath) throws IOException {

BloomFilter bloomFilter = new BloomFilter(225 1024 1024);

BufferedReader reader = new BufferedReader(new FileReader(inputPath));

BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath));

String line;

final int BATCH_SIZE = 10000;

while ((line = reader.readLine()) != null) {

int num = Integer.parseInt(line);
// 分批将数据存入Bloom Filter
bloomFilter.add(num);  
if (bloomFilter.size() % BATCH_SIZE == 0) {
  bloomFilter.flush(); // 持久化到磁盘
}

}

reader.close();

reader = new BufferedReader(new FileReader(inputPath));

// 再次遍历,检查哪些元素未命中

while ((line = reader.readLine()) != null) {

int num = Integer.parseInt(line);
if (!bloomFilter.check(num)) {
  writer.write(line + "\n");
}

}

writer.close();

reader.close();

}

这里为了避免Bloom Filter过大,使用了分批持久化的策略,避免内存溢出。二次遍历时只检查元素是否在Bloom Filter中,而不需要加载集合本身。

总结

对于内存无法容纳的超大数据集,使用Bloom Filter可以实现高效地去重和查询。相比传统方法,具有以下优势:

  • 内存占用小,只需要225MB内存即可处理25亿数据;
  • 只需要两轮遍历即可完成,效率较高;
  • 通过间隔查询代替遍历集合,降低内存压力。 当然Bloom Filter也存在一定误判率,需要权衡参数 另外,如果对容错要求较高,可以考虑使用HyperLogLog这种固定内存的数据结构。它可以精确计算巨大数据流distinct值,标准误差是0.8%。实现方法是维护每个元素的估计基数。 对于更复杂的业务场景,例如需要统计不同数字的频数,可以考虑使用Count-Min Sketch这种数据流统计算法。它使用多个哈希函数在多行计数器上统计频数,可以容忍一定程度的 hash 冲突。 无论使用何种算法,SPACE-TIME TRADEOFF是必须权衡的。内存受限情况下处理大数据问题,需要深入理解数据结构与算法的特性,权衡时间空间效率的平衡,设计出针对特定问题的优化方案。 本文给出了一种基于Bloom Filter解决大整数去重问题的设计思路。虽然无法覆盖所有场景,但希望可以作为算法设计的一个模板

标签:元素,reader,Filter,内存,受限,亿级,new,Bloom
From: https://blog.51cto.com/u_16188843/7079701

相关文章

  • 内存四区
    1.全局区c++中在运行前分为全局区和代码区。代码区的特点是共享和只读。全局区中存放全局变量、静态变量、常量。常量中存放const修饰的全局变量和字符串常量。2.栈区:局部变量、形参数据注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。3.堆区由程序员分配释放内存......
  • IronPython内存释放问题
    先给出优化后的代码:varoptions=newDictionary<string,object>{["LightweightScopes"]=true};ScriptEngineeng=IronPython.Hosting.Python.CreateEngine(AppDomain.CurrentDomain,options);varscope=eng.CreateScope();using(varstreamOut=n......
  • volatility3处理虚拟机内存快照报错
    准备工作python3.7以上https://github.com/volatilityfoundation/volatility3#安装pipinstallvolatility3#使用vol.exe-vvv-ftest-Snapshot1.vmemhashdump-vvv显示详细的报错信息-f指定内存镜像hashdump获取账号密码hash生成Linux下的standalone文件在Li......
  • SSLSocketImpl导致内存飙高
    SSLSocketImpl导致内存飙高问题现象所有服务容器内存都飙高,基本都到98%,但是一直不挂,但是有个节点,是xxljob一直调用的,到达98%以后,xxljob继续调用,就会oom重启,并且内存是缓慢的一直提升。MAT内存快照分析使用MAT,打开hrpof内存快照文件查看OverviewPane就是点击小i点击Leak......
  • ue4游戏逆向之GName内存解析(4.23版本以下)
    ue4游戏中的所有对象名称都保存在GName中,4.23版本以下的GName解析与高版本的不同。4.23版本以下可以通过'FName::GNames()'获取到GName指针,对应的GName指针就是staticTNameEntryArray*Names,利用ue4Dumper时输入的GName就是这个静态指针变量。'TNameEntryArray'类型是通过类模......
  • 《深入理解Java虚拟机》读书笔记:内存分配策略
    Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象的内存。关于回收内存这一点,我们已经使用了大量篇幅去介绍虚拟机中的垃圾收集器体系以及运作原理,现在我们再一起来探讨一下给对象分配内存的那点事儿。对象的内......
  • C语言中如何进行动态内存分配和释放
    动态内存分配和释放是C语言中非常重要的概念,它允许在程序运行时动态地申请和释放内存空间,提高程序的灵活性和效率。本文将围绕这一主题,详细介绍C语言中如何进行动态内存分配和释放。在C语言中,动态内存分配和释放主要通过malloc()和free()函数实现。malloc()函数用于申请一块指定......
  • 进程地址空间(虚拟内存)
    进程地址空间,进程虚拟内存的管理。某个进程地址空间的全部区域可以以红黑树+链表的形式存放。内核线程没有mm_struct没有进程地址空间,没有相关的内存描述符,这也是内核线程的真实含义--它们没有用户上下文。当一个进程被调度时,该进程的mm域指向的地址空间被装载到内存,PCB中的acti......
  • 内存管理
    内核把物理页作为内存管理的基本单位,内核用一个page结构体表示内核中的每个物理页。Linux把系统的页划分为区,形成不同的内存池,根据用途分配。区只是内核为了管理页而采用的一种逻辑上的分组。一些分配释放相关函数alloc_pages,该函数分配连续的物理页,返回一个指针指向第一个......
  • 内存管理
    内存管理python——内存管理python的内存管理机制:引用计数、垃圾回收,内存池机制接口:gc.disable()#暂停自动垃圾回收.gc.collect()#执行一次完整的垃圾回收,返回垃圾回收所找到无法到达的对象的数量.gc.set_threshold()#设置Python垃圾回收的阈值.gc.set_debug(......