如何在 Java 中利用 BitSet 实现针对千万级用户标签的位图过滤并极大地压缩内存占用

大杰吖_5294

大杰吖_5294

2026-05-01

588人浏览

原创

BitSet实现千万级用户标签过滤的核心是:用户ID映射为连续位索引,每标签一BitSet,批量位运算加速,并可选布隆过滤器预筛;内存仅约1.25MB/标签,支持毫秒级集合运算。

如何在 java 中利用 bitset 实现针对千万级用户标签的位图过滤并极大地压缩内存占用

用 BitSet 对千万级用户打标签并做高效过滤,核心在于:**把“用户ID → 位索引”映射固化、避免稀疏存储、批量操作位、配合布隆过滤器预筛(可选)**。Java 的 BitSet 底层是 long 数组,每 64 位仅占 8 字节,1000 万用户只需约 1.25 MB 内存(10⁷ ÷ 8 ÷ 1024 ÷ 1024),远低于布尔数组(≈10 MB)或 HashMap(≈100+ MB)。

一、用户 ID 必须规整且从 0 开始连续编号

这是 BitSet 高效的前提。真实业务中用户 ID 往往是字符串或长整型(如 10000000000000001),不能直接当 bit 索引。需构建轻量级映射:

  • 若用户注册有序、ID 自增(如 MySQL AUTO_INCREMENT),可用 userID - minID 作为 bitIndex;
  • 若 ID 是 UUID 或雪花 ID,需建立「ID → int 序号」的只读映射表(如用 ConcurrentMap + AtomicInteger 预分配,或离线生成 id2index 文件);
  • 不建议运行时动态扩容映射表——会破坏 BitSet 的 O(1) 时间优势;
  • 示例:1000 万用户,最大序号 9999999,bitSet.set(9999999) 自动扩容到位图长度 10⁷,内部仅分配约 156250 个 long(10⁷ ÷ 64 ≈ 156250)。

二、按标签维度建 BitSet,而非按用户维度

别为每个用户存一个 BitSet(爆炸式内存),而是**每个标签对应一个 BitSet**,bitIndex 表示“该用户是否拥有此标签”:

  • 例如标签 "vip":bitSetVip.get(uidIndex) == true 表示该用户是 VIP;
  • 标签 "ios"、"female"、"active_7d" 各自独立 BitSet;
  • 内存开销 = 标签数 × (用户数 ÷ 8) 字节;100 个标签 × 1000 万用户 ≈ 125 MB —— 仍远低于对象集合;
  • 支持快速交集(and)、并集(or)、差集(andNot):如找“VIP 且近 7 天活跃”的用户,bitSetVip.and(bitSetActive7d),毫秒级完成。

三、使用 getBulk() + long[] 批量操作提升吞吐

单次 get(i) 或 set(i) 有方法调用开销;对千万级批量处理(如全量导出、统计),应绕过逐位访问:

Java 接口排错助手
Java 接口排错助手

在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。

下载
  • 调用 BitSet.toLongArray() 获取底层 long 数组快照;
  • 手动遍历 long 数组,用位运算提取每一位:for (int i = 0; i > j) & 1) == 1; ... } };
  • 写入时同理:构造 long 数组后,用 BitSet.valueOf(longArr) 重建,比循环 set() 快 5–10 倍;
  • 注意:toLongArray() 返回的是逻辑长度(含末尾 0),不是物理容量,安全可靠。

四、结合稀疏优化与磁盘/Redis 持久化(超大规模场景)

若标签覆盖率极低(如“下单过奢侈品”只有 0.1% 用户),可用 BitSet.stream() 获取置位索引流,转为 RoaringBitmap(对稀疏数据压缩率更高),或存为 SortedSet 到 Redis:

  • 高频查询标签(如“登录过”)保留内存 BitSet;
  • 低频/稀疏标签走 RoaringBitmap(Apache Commons / CRoaring 库),压缩比可达 10x–100x;
  • 全量 BitSet 定期序列化为文件(ObjectOutputStream 或 Kryo),启动时 mmap 加载,避免 GC 压力;
  • 集群部署时,用 Redis Bitmap(SETBIT)分片存储,配合 Lua 脚本做服务端交集,减少网络传输。

不复杂但容易忽略:务必预估最大用户量设置初始容量(new BitSet(maxUserId + 1)),避免频繁扩容;所有 BitSet 操作保持无锁设计,多线程只读完全安全,写操作加轻量级分段锁或用 CopyOnWrite。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

java

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

12097

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

9182

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7852

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1284

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

1028

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1536

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3169

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20411

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1395

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习