Redis 命令及数据类型 -- RoaringBitmap

摘要

RoaringBitmap 命令

  • 可以在 redis-cli 中执行 help @module,找出所有 R.*R64.* 的命令说明

  • R.*:操作的是 32 位无符号整数(最大约 2^32-1)

  • R64.*:操作的是 64 位无符号整数(最大约 2^64-1),适合超大 ID 空间,如 Snowflake / 时间戳映射

    R64.* 支持的整数理论上是 0 ~ 2⁶⁴-1(约 1.84e19),但工程上应谨慎使用超大 offset,避免稀疏爆炸和性能退化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    high 32 bits  -> container key 大桶
    low 32 bits -> container offset 小桶

    当你写入一个非常大的值,例如 10^18
    虽然 Roaring 只为存在数据的 container 分配内存。
    但 container 的 key 本身是一个 map / array 索引结构。
    极端稀疏、超大 offset 会增加索引管理成本,会导致某些命令操作会变得很慢。
    另外,一个容器至少要 几十字节 ~ 几百字节级别,容器的数量过多,单机内存也无法满足
    如果你创建 10 亿个 container,假设每个 container 占用 100 字节,那么内存占用为:
    10^9 containers × 100 bytes ≈ 100 GB 内存
  • 两者语义完全一致,仅支持的 offset 范围不同,以下示例以 R.* 为主。

  • 对比 R 与 R64

维度 R.* R64.*
Offset 类型 uint32 uint64
最大值 4,294,967,295 (~4.29e9) 18,446,744,073,709,551,615 (~1.84e19)
可表达规模 十亿级 万亿亿级
典型用途 用户ID、索引 时间戳、雪花ID、全局唯一ID

一、数据写入 / 修改类

命令 功能 典型用途 示例
R.SETBIT 设置单个 bit(0/1),返回旧值 单点标记 R.SETBIT users 1001 1
R.SETRANGE 批量设置区间 bit=1 连续区间打标 R.SETRANGE users 3000 3999,不包含3999
R.APPENDINTARRAY 追加多个整数(bit=1) 批量插入 ID R.APPENDINTARRAY users 1001 1002 1003
R.SETINTARRAY 用整数数组重建 bitmap 初始化数据 R.SETINTARRAY users 1 3 5 7
R.SETBITARRAY 用 bit 字符串重建 bitmap 外部导入 R.SETBITARRAY users "101001"
R.DELETEINTARRAY 删除多个整数(bit=0) 批量删除 R.DELETEINTARRAY users 1002 2000
R.CLEARBITS 清除指定 offset 精确清理 R.CLEARBITS users 1001 1003
R.SETFULL 填充整个 bitmap 全量初始化 R.SETFULL users
R.CLEAR 删除整个 bitmap 释放资源 R.CLEAR users

二、数据读取 / 查询类

命令 功能 典型用途 示例
R.GETBIT 获取单个 bit 判断是否存在 R.GETBIT users 1001
R.GETBITS 批量获取 bit 多点查询 R.GETBITS users 1001 1002 1003
R.GETBITARRAY 返回完整 bit 字符串 调试 / 导出 R.GETBITARRAY users
R.GETINTARRAY 返回所有为 1 的整数 全量遍历 R.GETINTARRAY users
R.RANGEINTARRAY 返回区间内整数,注意这里参数是索引下标,不是数值 分页扫描 R.RANGEINTARRAY users 1 5
R.MIN 最小 offset 最小 ID 查询 R.MIN users
R.MAX 最大 offset 最大 ID 查询 R.MAX users

三、统计类

命令 功能 典型用途 示例
R.BITCOUNT bit=1 数量统计 集合基数 R.BITCOUNT users
R.BITPOS 查找第一个 1 或 0 稀疏分析 R.BITPOS users 1
R.MIN 最小 bit 位置 边界检测 R.MIN users
R.MAX 最大 bit 位置 边界检测 R.MAX users
R.STAT 容器 / 内存统计 性能调优 R.STAT users TEXT

四、集合运算类

命令 功能 集合语义 示例
R.BITOP AND 位图交集 A ∩ B R.BITOP AND res a b
R.BITOP OR 位图并集 A ∪ B R.BITOP OR res a b
R.BITOP XOR 对称差集 A ⊕ B R.BITOP XOR res a b
R.DIFF 差集 A - B R.DIFF res a b
R.CONTAINS 包含关系判断 子集检测 R.CONTAINS a b ALL
R.JACCARD 相似度计算 J(A,B) R.JACCARD a b

五、维护 / 优化类

命令 功能 典型用途 示例
R.OPTIMIZE 容器重整 / 压缩 降低内存 R.OPTIMIZE users MEM
R.CLEAR 清理 bitmap 回收资源 R.CLEAR users

六、R / R64 对照表(含示例)

功能 R (32bit) R64 (64bit) 示例
设置 bit R.SETBIT R64.SETBIT R64.SETBIT users64 90000000000 1
批量插入 R.APPENDINTARRAY R64.APPENDINTARRAY R64.APPENDINTARRAY users64 90000000001 90000000002
查询 bit R.GETBIT R64.GETBIT R64.GETBIT users64 90000000001
统计 R.BITCOUNT R64.BITCOUNT R64.BITCOUNT users64
集合运算 R.BITOP R64.BITOP R64.BITOP OR res64 a64 b64
优化 R.OPTIMIZE R64.OPTIMIZE R64.OPTIMIZE users64 MEM

真实案例

  • 场景说明

1
2
3
4
5
6
7
8
9
10
11
12
假设我们有一个电商平台,需要统计以下指标:
VIP 用户(购买金额超过 1000 的用户)
付费用户(至少购买一次的用户)
最近活跃用户(过去 7 天内登录过的用户)

我们想要计算:
VIP 用户人数
VIP 且最近活跃的用户人数
VIP 且付费用户且最近活跃的人数
付费用户与最近活跃用户的 Jaccard 相似度

假设用户 ID 为整数(最大值 < 2^32,使用 R.* 即可)。
    1. 写入数据(模拟)
1
2
3
4
5
6
7
8
9
10
11
12
# VIP 用户
R.APPENDINTARRAY vip_users 1001 1002 1003 1004 1005

# 付费用户
R.APPENDINTARRAY paid_users 1002 1003 1005 1006 1007

# 最近活跃用户
R.APPENDINTARRAY active_users 1001 1003 1005 1008

# 查看数据类型
127.0.0.1:6379> type active_users
reroaring
    1. 查询基础统计
1
2
3
4
5
6
7
8
9
10
11
# VIP 用户人数
R.BITCOUNT vip_users
# 返回 5

# 最近活跃用户人数
R.BITCOUNT active_users
# 返回 4

# 付费用户人数
R.BITCOUNT paid_users
# 返回 5
    1. 计算交集 / 子集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1.VIP 且最近活跃用户
R.BITOP AND vip_active vip_users active_users
R.BITCOUNT vip_active
# 返回 3
# 解释:用户 1001, 1003, 1005 同时是 VIP 且最近活跃。


# 2.VIP 且付费用户且最近活跃
# 先计算 VIP 与付费交集
R.BITOP AND vip_paid vip_users paid_users
# 再计算 vip_paid 与活跃用户交集
R.BITOP AND vip_paid_active vip_paid active_users
R.BITCOUNT vip_paid_active
# 返回 2
# 解释:用户 1003, 1005 同时满足三条件。
    1. 计算 Jaccard 相似度
1
2
3
4
5
6
# 计算 付费用户 与 最近活跃用户 的相似度
R.JACCARD paid_users active_users
# 返回 "0.2857142857142857"
# Jaccard 相似度计算公式:
J(A, B) = |A ∩ B| / |A ∪ B| = 交集 / 并集
0.2857142857142857 = |1003, 1005| / |1001, 1002, 1003, 1005, 1006, 1007, 1008| = 2 / 7 = 0.2857142857142857

J(A,B)=ABABJ(A, B) = \frac{|A \cap B|}{|A \cup B|}

    1. 范围 / ID 查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1.获取 VIP 用户 ID 列表
R.GETINTARRAY vip_users
# 输出
1) (integer) 1001 # 1 是索引,1001 是值
2) (integer) 1002
3) (integer) 1003
4) (integer) 1004
5) (integer) 1005

# 2.获取最近活跃用户 ID,索引范围 在 1~3 范围,注意这里的索引是 R.GETINTARRAY 返回的索引下标,不是值。
R.RANGEINTARRAY active_users 1 3
# 返回 1003, 1005, 1008
1) (integer) 1003
2) (integer) 1005
3) (integer) 1008

    1. 优化存储
1
2
3
4
# 如果数据量非常大,可以优化内存
R.OPTIMIZE vip_users MEM
R.OPTIMIZE paid_users MEM
R.OPTIMIZE active_users MEM