你一定要知道Redis的bitmap

redis
#1

你一定要知道Redis的bitmap

如果问你redis支持哪些数据类型,蛮多人都会说5种。Redis5 又新增了一种 Stream。其实 Redis 很久以前就支持另外三种数据类型

  • bitmaps
  • hyperloglogs
  • geospatial

Bitmaps 是啥?

也是一个key和value组成。但是这个value是由 2^31Bit组成。一个Bit的值除了是 0,就是 1

基本的语法

setbit [key] [offset] [value]

  • key 就是Key的名称
  • offset 偏移量,也就是 0 - 2^32-1

    可以把value看做是一个数组,offset就是下标

  • value 设置的,只能是 1 或者 0

bitop [operations] [result] [key1] [keyn…]

由bimpa存储的就是比特位,可以执行一些列位移计算

  • operations 位移操作符,枚举值

    • AND 与运算 &
    • OR 或运算 |
    • XOR 异或 ^
    • NOT 取反 ~
  • result 计算的结果,会存储在该key中

  • key1 … keyn 参与运算的key,可以有多个,空格分割

    NOT 只能有一个 key,因为是取反操作。

bitcount [key] [start] [end]

返回指定key被设置为 1 的位的数量,可以通过 start, end 设置起始位置

bitpos [key] [value]

返回指定key中第一次出现指定value(0/1)的位置

有啥用?

作为布隆过滤器的实现

关于布隆过滤器是啥,可以自己先通过搜索引擎去了解。

用于一些统计业务场景

例如有个需求,统计每天所有用户的登录情况。一个礼拜出一次汇报记录。分析哪些用户连续登录了,哪些用户没连续登录。哪些用户一次都没登录

先不说使用什么存储方式去统计。如果用一个Boolean值,表示用户是否登录过。起码也需要一个字节。而表示一个用户是否登录过,其实仅仅存在2种情况。要么登录过,要么没。非0即1。一个字节占8bit。显得有点浪费。使用bitmap就可以非常好的表示。

一个bitmap有2^32个比特位。也就是:1L << 32; // 4294967296 可以根据用户的id作为offset(40多亿够够的)。每天一个新生成一个bitmap key。如果用户登录了。就把他的id对应的offset设置为1。

统计起来也是非常的方便,redis本身就支持这种位移运算。可以快速的得到结果(不懂位移运算,先通过搜索引擎了解)
把前几天的所有bitmap进行一个 & 运算,得到结果。如果offset = 1, 就表示该用户几天都有连续登录。
把前几天的所有bitmap进行一个 | 运算,得到结果。如果offset = 1, 就表示该用户几天起码登录过一天。

使用 lettuce 客户端操作bitmap

RedisClient redisClient = RedisClient.create("redis://localhost:6379/0");
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> syncCommands = connection.sync();

// 设置和读取bit
syncCommands.setbit("users",1,1);
syncCommands.getbit("users",1);

// 位移预算
syncCommands.bitopAnd("result","key1","key2");
syncCommands.bitopOr("result","key1","key2");
syncCommands.bitopXor("result","key1","key2");
syncCommands.bitopNot("result","key1");