redis 位图操作

  这里说下redis 的位图,在学习 redis 位图的时候,被它的一些应用场景给惊艳到了,特此记录下。

  1个字节( b ) = 8位( bit ) = 0.001 千字节( kb )

 redis 位图命令

   setbit 

      指定字符串偏移的位的值

setbit key offset value

  setbit 官方文档:https://redis.io/commands/setbit  ,也可以参考这个中文版的:http://redisdoc.com/bitmap/setbit.html

对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。当 key 不存在时,自动生成一个新的字符串值。字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内) 。对于大偏移量的setbit 操作申请内存会花费一定的时间。

 getbit 

       获取指定偏移量上的位 ,当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。

getbit key offset

 使用位图操作来进行字符串大小写转换

  A   ===== >    65    0100 0001
  a   ===== >     97    0110 0001

A 与 a 在二进制位表示,在第 3 位上表示为1 ,将第3位(偏移量为2,偏移量是从0开始的)设置为1即可转换成a 

127.0.0.1:6379> set character A
OK
127.0.0.1:6379> get character 
"A"
127.0.0.1:6379> setbit character 2 1
(integer) 0
127.0.0.1:6379> getbit character 2
(integer) 1
127.0.0.1:6379> get character
"a"
127.0.0.1:6379> 

  bitcount    

       统计字符串被设置为1的bit数

bitcount key [start end]

参考地址:https://redis.io/commands/bitcount 

      一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。

案例:使用 bitmap 实现用户上线次数统计

  假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 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 上线的总天数。

性能分析

 前面的上线次数统计例子,即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, BITCOUNT 的处理速度就像 GET 和 INCR 这种 O(1) 复杂度的操作一样快。

如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:

  1. 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
  2. 使用 BITCOUNT key [start] [end] 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。

这个例子,可以在redis 官方文档:https://redis.io/commands/bitcount 有讲,当然也有中文版的:http://www.redis.cn/commands/bitcount.html

bitop

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

bitop operation destkey key [key ...]

BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作,除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。

参考地址:https://redis.io/commands/bitop

例子

127.0.0.1:6379> set str1 "foobar"
OK
127.0.0.1:6379> set str2 "abcdef"
OK
127.0.0.1:6379> bitop and str1 str1 str2
(integer) 6
127.0.0.1:6379> get str1
"`bc`ab"
127.0.0.1:6379> 

foobar 

             f  ===  >  102  0110 0110           o ===  >  111  0110 1111                          o ===  >  111  0110 1111
             b ===  >   98   0110 0010           a ===  >   97   0110 0001                         r  ===  >  114  0111 0010

       =============================================================================

abcdef

a ===  >  97   0110 0001                       b ===  >  98   0110 0010                           c ===  >   99    0110 0011
d ===  >  100   0110 0100                     e ===  >   101   0110 0101                         f ===  >   102   0110 0110

结果:

    0110 0110    0110 1111   0110 1111   0110 0010   0110 0001   0111 0010
    0110 0001    0110 0010   0110 0011   0110 0100   0110 0101   0110 0110

and 
----------------------------------------------------------------------------------------------------------------------------------
  0110 0000    0110 0010    0110 0011  0110 0000    0110 0001    0110 0010
        96                 98                  99                 96             97                98
---------------------------------------------------------------------------------------------------------------------------------       
       `                     b                     c                   `                 a                 b    
               

案例:

      上亿个用户,统计一周内连续活跃用户。

可以结合setbit ,bitop 来实现:以周为key ( 比如周一则 key 为mon,周二 key 为tues ),uid 为500 的用户周一上线了,则用 setbit 把mon将偏移量为500的值设置为1,uid 为501的用户周一上线了,用 setbit 把mon将偏移量为501的值设置为1 ,uid 为501的用户周日上线了,用 setbit 把sun( 周日的key )将偏移量为501的值设置为1 ,以此类推。

最后统计一周内连续活跃用户数,可以使用sitop and res mon tues ... sun 。

拿到结果后,只需要判断第几位值位1,则代表该位所代表 uid 用户一周内连续登陆。

以上案例,1亿人每天登陆情况,用1亿bit约10M的空间就能表示,一年也才不到4个G的空间就能存储。

这里写的比较基础,深入可以参考:https://blog.csdn.net/u011957758/article/details/74783347 。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值