Redis:Bitmap的setbit,getbit,bitcount,bitop等使用与应用场景

详细介绍redis中bitmap的相关命令用法以及使用场景如:用户上下线记录、日活月活留存率等统计计算

  • 简介
    • 优点
    • 缺点
  • Redis Getbit 命令
  • Redis Setbit 命令
  • Redis Bitcount 命令
  • Redis Bitop 命令
  • 应用场景
    • 1.可作为简单的布尔过滤器来判断用户是否执行过某些操作
    • 2.用户日活,月活,留存率的统计
    • 3.实现用户上线次数统计
    • 4.用户在线状态及人数统计记录

官方redis教程

简介

几个前提:

  • 数据在redis中都是二进制存储
  • setbit和getbit和bitcount是string数据类型的命令
  • 8bit表示一个ascll字符,因为是c写的redis
  • offset偏移量是从0开始

操作String数据结构的key所存储的字符串值指定偏移量上的位,返回的是原位置上的值

优点

  • 极其省空间:通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。
  • 极其效率高:setbit和getbit的时间复杂度就是O(1),其他位运算也是效率极高的

空间占用、以及第一次分配空间需要的时间:

在一台2010MacBook Pro上,offset为2^32-1(分配512MB)需要~300ms,offset为2^30-1(分配128MB)需要~80ms,offset为2^28-1(分配32MB)需要~30ms,offset为2^26-1(分配8MB)需要8ms。<来自官方文档>
大概的空间占用计算公式是:($offset/8/1024/1024)MB

缺点

缺点也在于位计算和位表示数值的局限。故如要用位来做业务数据记录,那么就不要在意value的值了

Redis Getbit 命令

对 key 所储存的字符串值,获取指定偏移量上的位(bit)。

  • 语法:getbit key offset 注:offset表示偏移量
  • 返回值:字符串值指定偏移量上的位(bit)。当偏移量 OFFSET 比字符串值的长度大,或者 key 不存在时,返回 0 。

案例:

127.0.0.1:6379> set A a
OK
127.0.0.1:6379> get A
"a"
127.0.0.1:6379> getbit A 0
(integer) 0
127.0.0.1:6379> getbit A 1
(integer) 1
127.0.0.1:6379> getbit A 2
(integer) 1
127.0.0.1:6379> getbit A 3
(integer) 0
127.0.0.1:6379> getbit A 4
(integer) 0
127.0.0.1:6379> getbit A 5
(integer) 0
127.0.0.1:6379> getbit A 6
(integer) 0
127.0.0.1:6379> getbit A 7
(integer) 1

Redis Setbit 命令

对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。

  • 语法:
    setbit key offset value
  • 返回值:指定偏移量原来储存的位。

案例:将上述A的值“a”的第6位修改为1,也就是相当于ASCLL码加2,从而值从a变成了c。

127.0.0.1:6379> setbit A 6 1
(integer) 0
127.0.0.1:6379> get A
"c"
127.0.0.1:6379> 

Redis Bitcount 命令

计算给定key的字符串值中,被设置为 1 的比特位的数量。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。

  • 语法:BITCOUNT key [start] [end]
  • 返回值:1比特位的数量

案例:值c的二进制数应该是01100011,故bitcount计算出来应该是4

127.0.0.1:6379> get A
"c"
127.0.0.1:6379> bitcount A
(integer) 4

Redis Bitop 命令

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上

  • 语法: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 的字符串序列。

  • 可用版本:>= 2.6.0

  • 时间复杂度:
    O(N)

    BITOP 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。

  • 案例:

127.0.0.1:6379> set E a
OK
127.0.0.1:6379> set F b
OK
127.0.0.1:6379> set G d
OK
127.0.0.1:6379> bitop and andEFG E F G
(integer) 1
127.0.0.1:6379> get andEFG
"`"
127.0.0.1:6379> bitop or orEFG E F G
(integer) 1
127.0.0.1:6379> get orEFG
"g"
127.0.0.1:6379> bitop xor xorEFG E F G
(integer) 1
127.0.0.1:6379> get xorEFG
"g"
127.0.0.1:6379> bitop not notE E
(integer) 1
127.0.0.1:6379> get notE
"\x9e"

注:

  • 值a的2进制数据为:01100001;
  • 值b的2进制数据为:01100010;
  • 值d的2进制数据为:01100100;

得出来的值可以去查下ascll码表应该是正确的

应用场景

首先,这两个命令是效率极高且省内存,因为直接操作的是redis存储的数据。

一般应用场景:

1.可作为简单的布尔过滤器来判断用户是否执行过某些操作

2.用户日活,月活,留存率的统计

案例:

  • 需求:每个用户登陆/做任意操作 ,记为 今天活跃,否则记为不活跃。计算出日活7日活月活等数据。

  • 具体实施:使用redis的bitmap

    • 设置一个key专门用来记录用户日活的,可以使用时间来翻滚比如1号的key为active01.
    • 使用每个用户的唯一标识映射一个偏移量,比如使用id,这里可以把id换算成一个数字或直接使用id的二进制值作为该用户在当天是否活跃偏移量
    • 用户登录则把该用户偏移量上的位值设置为1
    • 每天按日期生成一个位图(bitmap)
    • 计算日活则使用bitcount即可获得一个key的位值为1的量
    • 计算月活(一个月内登陆的用户去重总数)即可把30天的所有bitmap做or计算,然后再计算bitcount
    • 计算留存率(次日留存=昨天今天连续登录的人数/昨天登录的人数) 即昨天的bitmap与今天的bitmap做and计算就是连续登录的再做bitcount就得到连续登录人数,再bitcount得到昨天登录人数,就可以通过公式计算出次日留存。
      如下案例:
      127.0.0.1:6379> bitop and andValue A B
      (integer) 1
      127.0.0.1:6379> get andValue
      "b"
      127.0.0.1:6379> bitop or orValue A B
      (integer) 1
      127.0.0.1:6379> get orValue
      "c"
      127.0.0.1:6379> bitcount andValue
      (integer) 3
      127.0.0.1:6379> bitcount orValue
      (integer) 4

3.实现用户上线次数统计

  • 假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT 和 BITCOUNT 来实现。
  • 比如说,每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。
  • 举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。
  • 当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。

4.用户在线状态及人数统计记录

同样是使用一个bitmap,用用户的id来映射偏移量,在线标识为1,下线标识为0。可以轻松实现用户上下线查询和总在线人数的统计等等

参考:

  • Redis中bitmap的妙用
  • 用户上线统计:Fast, easy, realtime metrics using Redis bitmaps

你可能感兴趣的:(Redis)