直接用JDK BitSet做千万级用户标签交并集不可行,因其不支持分布式、无压缩、内存爆炸、ID非连续导致浪费严重、无序列化协议、不支持稀疏优化、缺乏批量位运算能力。

直接用 BitSet 在 Java 里做千万级用户标签交并集,基本不可行——它不支持分布式、无压缩、内存爆炸、无法跨 JVM 同步,线上系统一跑就 OOM。
为什么不能直接用 JDK 的 BitSet
它只是个单机位数组工具类,不是为画像场景设计的:
-
BitSet每个 bit 对应一个用户 ID,但用户 ID 通常是随机 long(如 1234567890123),不是从 0 开始连续递增;强行映射会浪费大量内存(比如最大 ID 是 10 亿,BitSet就要分配 125MB) - 没有内置序列化/反序列化协议,无法存 Redis 或写 Hologres;跨服务传递只能靠
toByteArray(),但字节数组大小随用户量线性增长,网络开销大 - 不支持 RoaringBitmap 那种稀疏优化:当用户集合稀疏(比如“购买过某冷门商品”的用户只占 0.1%),
BitSet仍按全量位宽分配,而 RoaringBitmap 只存实际有数据的 container - 没有原生
AND/OR/ANDNOT的批量合并能力,多标签计算得手动循环 set/get,性能掉到 O(n)
Hologres 中必须用 roaringbitmap 函数而非 bitand
PostgreSQL 原生的 bitand 只支持固定长度的 BIT 类型(如 BIT(1000)),完全不适合用户 ID 动态分布的画像场景。Hologres 的 roaringbitmap 插件才是正解:
- 输入是用户 ID 列表或子查询结果,自动编码为 RoaringBitmap 格式:
rb_build_agg(user_id) - 交集用
rb_and(bm1, bm2),并集用rb_or(bm1, bm2),差集用rb_andnot(bm1, bm2),全部是 C++ SIMD 加速,毫秒完成十亿级运算 - 存储上自动分 container(array/container/ bitmap),对“近 7 天活跃”这类稀疏标签,内存占用比
BitSet低 10–100 倍 - 支持直接与普通表 JOIN:
SELECT count(*) FROM users WHERE rb_contains(tag_bitmap, user_id),避免全表扫描
标签 Bitmap 构建时最容易踩的坑:ID 编码方式
不是所有用户 ID 都能直接喂给 rb_build_agg()。关键在编码是否“紧凑”:
- 若原始用户 ID 是 UUID 或雪花 ID(如
1234567890123456789),直接聚合会导致 RoaringBitmap 内部 container 范围过大,失去压缩优势 → 必须先做全局 ID 映射(例如用 Hologres 的row_number() over(order by user_id)生成 0-based 紧凑 ID) - 离线标签表和实时行为表的 ID 编码空间必须一致,否则
rb_and运算结果错乱;常见错误是离线用 Hive 分配 ID,实时用 Flink 分配,两边 offset 不对齐 - 不要在应用层用
BitSet.set(long index)手动构造再转 RoaringBitmap —— 序列化开销大且易出错;应该让 Hologres 在 SQL 层完成整个构建:INSERT INTO tag_bitmap_table SELECT 'female_25plus' as tag, rb_build_agg(user_id) FROM user_profile WHERE gender='F' AND age >= 25
当需要跨平台/跨设备圈选时,Bitmap 本身不解决 ID 统一问题
RoaringBitmap 只保证“给定一组 ID,快速算交并差”,但它不管这些 ID 是否代表同一个真实用户。如果 APP、小程序、PC 各自用不同 ID 体系:
- 必须前置做 device_id / open_id / uid 的 ID-Mapping(例如用 Doris 或 Hologres 的
MAP类型存映射关系表) - 再把映射后的统一 UID 作为
rb_build_agg()的输入,否则“APP 用户 ∩ 小程序用户”永远为空 - 映射表本身也要用 RoaringBitmap 存储(如
rb_build_agg(mapped_uid)),否则关联查 mapping 表又回到慢 SQL 老路
真正难的从来不是位运算本身,而是让每个标签背后的用户 ID 集合,在编码、存储、更新、跨源对齐这四个环节都不失真——错一步,rb_and 算出来的就是一堆无效 bit。

















