Skip to content

Instantly share code, notes, and snippets.

@lifeblood
Last active Feb 19, 2020
Embed
What would you like to do?
利用 Redis 位运算快速实现签到统计功能

BitMap是什么

就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。

Redis中的BitMap

Redis从2.2.0版本开始新增了setbit,getbit,bitcount等几个bitmap相关命令。虽然是新命令,但是并没有新增新的数据类型,因为setbit等命令只不过是在set上的扩展。

setbit命令介绍

BitMap 就是通过一个 bit 位来表示某个元素对应的值或者状态, 其中的 key 就是对应元素本身,实际上底层也是通过对字符串的操作来实现。Redis 从 2.2 版本之后新增了setbit, getbit, bitcount 等几个 bitmap 相关命令。虽然是新命令,但是本身都是对字符串的操作

Redis相关方法

  1. setbit: Redis Setbit 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。文档
  2. getbit: Redis Getbit 命令用于对 key 所储存的字符串值,获取指定偏移量上的位(bit)。文档
  3. bitcount: Redis Bitcount 计算给定字符串中,被设置为 1 的比特位的数量。文档
  4. bitop: Redis Bitop对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。文档

Redis key name 约定

$dayKey = 'login:'.\date('Ymd',\time());

Redis 数据结构

key sign:20200202 sign:20200203 sign:20200204 ...
offset (UserId) 1000 1001 1002 ...
value 0 1 1 ...
status 未签到 已签到 已签到 ...

使用场景

  1. 用户签到
  2. 统计活跃用户
  3. 用户在线状态

用户签到

$redis->setbit($dayKey, $this->user->id, 1);

可以看到在存储方面不仅耗费内存少,快,而且操作还方便,就这么一句话就搞定了

相关统计

  1. 命令 BITOP operation destkey key [key ...]
  2. 说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
  3. 说明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数
$redis->bitop('AND', 'threeAnd', 'login:20190311', 'login:20190312', 'login:20190313');
 echo "连续三天都签到的用户数量:" . $redis->bitCount('threeAnd');

 $redis->bitop('OR', 'threeOr', 'login:20190311', 'login:20190312', 'login:20190313');
 echo "三天中签到用户数量(有一天签也算签了):" . $redis->bitCount('threeOr');

 $redis->bitop('AND', 'monthActivities'', $redis->keys('login:201903*'));
 echo "连续一个月签到用户数量:" . $redis->bitCount('monthActivities');

 echo "当前用户指定天数是否签到:" . $redis->getbit('login:20190311', $this->user->id);
 .....

使用经验

string类型最大长度为512M。 注意setbit时的偏移量,当偏移量很大时,可能会有较大耗时。 位图不是绝对的好,有时可能更浪费空间。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment