场景题:假设有40亿QQ号,但只有1G内存,如何实现去重?

news/2025/1/9 9:11:15/文章来源:https://www.cnblogs.com/vipstone/p/18657860

当数据量比较大时,使用常规的方式来判重就不行了。例如,使用 MySQL 数据库判重,或使用 List.contains() 或 Set.contains() 判重就不行了,因为数据量太大会导致内存放不下,或查询速度太慢等问题。

1.空间占用量预测

正常情况下,如果将 40 亿 QQ 号存储在 Java 中的 int 类型的话,一个 int 占 4 字节(byte)那么 40 亿占用空间大小为:

4000000000*4/1024/1024/1024=14.9 GB

1GB=1024MB,1MB=1024KB,1KB=1024B(byte)

所以,我们无法使用正常的手段进行 40 亿 QQ 号的存储和去重判断,那怎么实现呢?

2.解决方案

此问题的常见解决方案有两种:

  1. 使用位数组 BitMap 实现判重。
  2. 使用布隆过滤器实现判重。

具体来说。

2.1 位数组实现判重

位数组是指使用位(bit)组成的数组,每个 QQ 号使用 1 位(bit)来存储,如下图所示:其中下标用来标识具体的数字,例如以上图片标识 1、3 数字存在,如果值为 0 表示不存在,这样的话 40 亿占用的位数组空间位 40 亿 bit,也就是 4000000000/1024/1024/1024/8=0.465 GB,不到 1G 的内存就可以存储 40 亿 QQ 号了,查询某个 QQ 号是否在线,只需要看这个 QQ 下标对应的位置是否为 1,1 表示存在,0 表示不存在。

位数组代码实现

位数组可以使用 Java 自带的 BitSet 来实现,它位于 java.util 包中,具体实现代码如下:

import java.util.BitSet;public class BitmapExample {public static void main(String[] args) {// 创建一个BitSet实例BitSet bitmap = new BitSet();// 设置第5个位置为1,表示第5个元素存在bitmap.set(5);// 检查第5个位置是否已设置boolean exists = bitmap.get(5);System.out.println("Element exists: " + exists);  // 输出: Element exists: true// 设置从索引10到20的所有位置为1bitmap.set(10, 21);  // 参数是包含起始点和不包含终点的区间// 计算bitset中所有值为1的位的数量,相当于计算设置了的元素个数int count = bitmap.cardinality();System.out.println("Number of set bits: " + count);// 清除第5个位置bitmap.clear(5);// 判断位图是否为空boolean isEmpty = bitmap.isEmpty();System.out.println("Is the bitset empty? " + isEmpty);}
}

2.2 布隆过器实现

布隆过滤器是基于位数组实现的,它是一种高效的数据结构,由布隆在 1970 年提出。它主要用于判断一个元素可能是否存在于集合中,其核心特性包括高效的插入和查询操作,但存在一定的假阳性(False Positives)可能性。

布隆过滤器实现如下图所示:

根据 key 值计算出它的存储位置,然后将此位置标识全部标识为 1(未存放数据的位置全部为 0),查询时也是查询对应的位置是否全部为 1,如果全部为 1,则说明数据是可能存在的,否则一定不存在

布隆过器特性:如果布隆过滤器说一个元素不在集合中,那么它一定不在这个集合中;但如果它说一个元素在集合中,则有可能是不存在的(存在误差,假阳性)。

布隆过器代码实现

布隆过滤器的常见实现有以下几种方式:

  1. 使用 Google Guava BloomFilter 实现布隆过滤器,具体实现代码如下:
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {public static void main(String[] args) {// 创建一个布隆过滤器,设置期望插入的数据量为10000,期望的误判率为0.01BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), 10000, 0.01);// 向布隆过滤器中插入数据bloomFilter.put("data1");bloomFilter.put("data2");bloomFilter.put("data3");// 查询元素是否存在于布隆过滤器中System.out.println(bloomFilter.mightContain("data1")); // trueSystem.out.println(bloomFilter.mightContain("data4")); // false}
}
  1. 使用 Hutool 框架 BitMapBloomFilter 实现布隆过滤器,如下代码所示:
// 初始化
BitMapBloomFilter filter = new BitMapBloomFilter(10);
// 存放数据
filter.add("123");
filter.add("abc");
filter.add("ddd");
// 查找
filter.contains("abc");
  1. 使用 Redisson 框架中的 RBloomFilter 实现布隆过滤器,如下代码所示:
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 创建布隆过滤器,设置名称和期望容量与误报率
RBloomFilter<String> bloomFilter = 
redissonClient.getBloomFilter("myBloomFilter");
bloomFilter.tryInit(10000, 0.03); // 期望容量 10000,误报率 3%
// 添加元素到布隆过滤器
String element1 = "element1";
bloomFilter.add(element1);
// 判断元素是否存在
boolean mightExist = bloomFilter.contains(element1);
System.out.println("元素 " + element1 + " 可能存在: " + mightExist);
String element2 = "element2";
boolean mightExist2 = bloomFilter.contains(element2);
System.out.println("元素 " + element2 + " 可能存在: " + mightExist2);

其中 Google Guava BloomFilter 和 Hutool 框架 BitMapBloomFilter 为单机版的布隆过滤器实现,不适用分布式环境。分布式环境要使用 Redisson 框架中的 RBloomFilter 来实现布隆过滤器,因为它的数据是保存在 Redis 中间件的,而中间件天生支持分布式系统。

小结

位数组和布隆过滤器的区别如下:

  • 位数组:没有误判,但空间利用率低。
  • 布隆过滤器:空间利用率高,但存在对已经存在的数据的误判(不存在的数据没有误判)。

因此,如果对精准度要求高可以使用位数组;如果对空间要求苛刻,可以考虑布隆过滤器。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:场景题、并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、JVM、设计模式、消息队列等模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865392.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Forensia:红队后渗透的痕迹清理工具

简介: 红队反取证工具,用于在后期利用阶段消除一些足迹,减少有效载荷消耗并增加检测倒计时。可用于测试事件响应/取证团队的能力。 功能: 卸载Sysmon驱动 Gutmann方法文件粉碎 USNJrnl功能失效 预取功能失效 日志橡皮擦和事件日志禁用 用户辅助更新时间禁用 访问时间禁用 清…

DirectX修复工具:系统修复必备神器 修复工具 V4.3 绿色增强版

DirectX修复工具是一款专用于修复系统异常的工具,DirectX修复工具还是一款使用简单易上手操作且绿色、可免安装的修复工具。使用DirectX修复工具可自动更新C++组件且完美修复0xc000007b问题异常。如果你的电脑出现了DirectX的异常问题,可直接下载DirectX修复工具进行修复解决…

浅谈异地访问家庭网络的几种方案

家庭网络如何实现公网访问?想必是大家一直在探索的问题。本文带领大家一起来探究适合自己的解决方案吧! 为什么要实现公网访问? 要回答这个问题,每个人的答案或许不一样。但归纳在一起就是三个字爱折腾。在前面的文章中,我们讲到了如何将旧电脑打造属于自己的NAS,而如何远…

Visual Studio 2022 上架腾讯云 AI 代码助手了

近期在Visual Studio 市场上上架了腾讯云 AI 代码助手。该插件可以在 Visual Studio2022 版本(含社区版,版本不低于 17.6 即可)使用智能辅助编码能力,助力 Visual Studio 的开发者提高效率。我们在该平台上支持技术对话、代码补全、单元测试生成、解释代码、修复代码等场景…

CDS标准视图:优先级描述数据 I_GenericPriorityTextData

视图名称:优先级描述数据 I_GenericPriorityTextData 视图类型:基础视图 视图代码:点击查看代码 @AbapCatalog.sqlViewName: IGENPRIOTEXTDATA @AbapCatalog.compiler.compareFilter: true @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: Generic P…

deeplearning4j~实现简单模型训练和测试

DeepLearning4j (DL4J) 是一个开源的深度学习库,专为 Java 和 Scala 设计。它可以用于构建、训练和部署深度学习模型。以下是关于如何使用 DL4J 的基本指南以及一个简单的模型训练示例。 本例中使用了MNIST数据集,MNIST(modified national institute of standard and techno…

云上攻防-云原生K8s安全实战场景攻击Pod污点Taint横向移动容器逃逸

云原生&K8s安全&实战场景&攻击Pod&污点Taint&横向移动&容器逃逸知识点 1、云原生-K8s安全-横向移动-污点Taint 2、云原生-K8s安全-Kubernetes实战场景 一、演示案例-云原生-K8s安全-横向移动-污点Taint 如何判断实战中能否利用污点Taint? 设置污点 ku…

深入解析 Spring AI 系列:项目结构一览

从今天起,我们将以 Spring AI 为主线,开始更新一系列的文章。这些文章将围绕 Spring AI 项目展开,结合我的理解,深入讲解其相关的知识点、技术原理、以及在实际开发过程中涉及到的部分代码实现等内容。通过这些文章,希望能够帮助大家更好地理解和使用 Spring AI。今天的主…

BUG:SWM32开机绘制lvgl框架下的某个自定义控件死机

一.BUG描述 现象1.画了一个关于"模式"的自定义控件,结果开机绘制总是死机。 现象2.用keil进行仿真调试全速运行同样死机,但是如果在异常处加断点,然后单步调试就正常。(注:仿真调试比直接运行的速度要慢) 现象3.把这个异常对象的创建代码删除,再后面加四个打印…

大镖客2--中文地图

下载GMM 从网站 https://gmm.aoe.top/ 下载GMM软件 双击安装GMM即可 下载前置 下载大镖客2前置 从我网盘下载: 通过网盘分享的文件:荒野大镖客2 Mod前置包.gmm链接: https://pan.baidu.com/s/1IRorQ9FO7Dy_LzU70U_uRw?pwd=6666 提取码: 6666 选择游戏 找到RDR2.exe文件 …

CDS标准视图:测量点数据 I_MeasuringPointData

视图名称:测量点数据 I_MeasuringPointData 视图类型:基础视图 视图代码:点击查看代码 @AbapCatalog.sqlViewName: IMEASPOINTDATA @AbapCatalog.compiler.compareFilter: true @AccessControl.authorizationCheck: #CHECK @EndUserText.label: Measuring Point Data@VDM.vi…

vxe-table 实现 excel 选择两个单元格,拖拽自动识别数字规则并根据规则自动填充新的单元格

vxe-table 实现 excel 选择两个单元格,拖拽自动识别数字规则并根据规则自动填充新的单元格 官网:https://vxetable.cn鼠标按住右下角扩展按钮,当选取一个单元格时,自动将当前内容填充到扩展区域的所有单元格中,如果不希望自动识别数字规则,可以同时按住 ctrl 键可取消值自…