Redis中的Bitmap和HyperLogLog

Redis中的Bitmap和HyperLogLog

  • Bitmap(位图)
    • Bitmap存储结构
    • Bitmap上的统计
      • bitcount count [start end]
      • bitop operation destkey key [key ...]
    • Bitmap的妙用
      • 用户在线状态
      • 用户签到
      • 统计活跃用户
  • HyperLogLog
    • HyperLogLog的指令
    • HyperLogLog使用场景
      • 统计页面UV
    • HyperLogLog原理

Bitmap(位图)

Bitmap存储结构

在Redis中以位为单位存储字符串,这种存储结构称为Bitmap,也叫位图。
每个字节存储结构如下:

offset 0 1 2 3 4 5 6 7
value 0 0 0 0 0 0 0 0
setbit key 0 1                      # 10000000
getbit key1 0                       # 1
get key1                            # "\x80"
setbit key2 1 1                     # 01000000
setbit key2 7 1                     # 01000001
get key2                            # "A"

get key时,如果找到ASCII对应的字符串直接返回字符串,否则16进制数字。

示例如下:
Redis中的Bitmap和HyperLogLog_第1张图片

Bitmap上的统计

bitcount count [start end]

setbit key 0 1                      # 10000000
setbit key 8 1                      # 10000000 10000000
setbit key 16 1                     # 10000000 10000000 10000000
bitcount key                        # 3
bitcount key -2 -1                  # 2
bitcount key -3 -1                  # 3

bitcount是根据字节统计每位数值为1的位数,而不是以位统计;
end参数-1表示最后一个字节;
start参数是根据end参数往前推导。

Redis中的Bitmap和HyperLogLog_第2张图片

bitop operation destkey key [key …]

operation可以是and、or、not、xor这四种操作中的任意一种。

  • bitop and destkey key [key …] ,对一个或多个key求逻辑并,并将结果保存到destkey;
  • bitop or destkey key [key …] ,对一个或多个key求逻辑或,并将结果保存到destkey;
  • bitop xor destkey key [key …] ,对一个或多个key求逻辑异或,并将结果保存到destkey;
  • bitop not destkey key ,对给定key求逻辑非,并将结果保存到destkey。

除了not操作外,其他操作都可以接受一个或多个key作为输入;
当bitop处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看做0;
空的key也被看作是包含0的字符串序列。

setbit 20200723 0 1                      # 10000000
setbit 20200724 0 1                      # 10000000
setbit 20200724 7 1                      # 10000001
bitop and key 20200723 20200724          # 10000000
bitcount key                             # 1
bitop or key 20200723 20200724           # 10000001
bitcount key                             # 2

Redis中的Bitmap和HyperLogLog_第3张图片

Bitmap的妙用

用户在线状态

使用bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户ID为offset,如果在线就设置为1,不在线就设置为0,和上面的场景一样,5000W用户只需要6MB的空间。

用户签到

设置一个日期作为开始日期,当用户签到时,使用用户id为key,当前日期到开始日期的天数为offset;

  1. 用户A第1天签到,用户id为1,setbit 1 1 1
  2. 用户B第2天签到,用户id为2,setbit 2 2 1
  3. 查询用户A第一天是否签到,getbit 1 1
  4. 计算用户A签到天数,bitcount 1

这里如果要根据日期范围来统计时就不能满足了,因为bitcount不是以位为单位来统计的,而是字节为单位统计;
如果要使用bitmap实现此需求,天数做offset时必须乘8,保证一天一个字节,统计时可直接使用天数计算start和end参数;
这种做法弊端就是使用了8倍的空间。

统计活跃用户

使用日期作为key,用户id作为偏移量,如果当天活跃,则设置value为1;

  1. 2020-07-23用户A活跃,用户id为1,setbit 20200723 1 1
  2. 2020-07-23用户B活跃,用户id为2,setbit 20200723 2 1
  3. 2020-07-24用户B活跃,用户id为2,setbit 20200724 2 1
  4. 假设日期范围内连续在线称为活跃用户,统计活跃用户数 bitop and key 20200723 20200724,bitcount key

HyperLogLog

HyperLogLog的指令

HyperLogLog提供了pfadd、pfcount和pfmerge指令,只占用12KB的空间

pfadd:将value加入集合中
pfcount:获取value计数值

pfadd key1 user1              #user1
pfadd key1 user2              #user1 user2
pfadd key1 user3              #user1 user2 user3
pfcount key1                  #3
pfadd key2 user3              #user3
pfadd key2 user4              #user3 user4
pfmerge key key1 key2         #user1 user23 user3 user4
pfcount key                   #4

Redis中的Bitmap和HyperLogLog_第4张图片

HyperLogLog使用场景

统计页面UV

以页面名称为key,访问页面的用户id为value,每次访问pfadd一次,统计时直接使用pfcount
不同页面的UV需要合并时,直接pfmerge,但是数据量大的时候,会有一定的误差

HyperLogLog原理

给定一系列随机整数样本,记录下低位连续零位的最大长度K,通过这个K值可以估算出样本数量N,即K和N具有线性相关性,不加权计算时,吻合下面公式曲线
N = 2 K N=2^K N=2K
Redis中使用16384个桶,加权计算得出N值

你可能感兴趣的:(Redis,redis)