redis学习-12- Redis bitmap位图操作

8.bitmap位图操作

  • 在平时开发过程中,经常会有一些 bool 类型数据需要存取。比如记录用户一年内签到的次数,签了是 1,没签是 0。如果使用 key-value 来存储,那么每个用户都要记录 365 次,当用户成百上亿时,需要的存储空间将非常巨大。为了解决这个问题,Redis 提供了位图结构。

  • 位图(bitmap)同样属于 string 数据类型。Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,这大大增加了 value 存储数量,它存储上限为2^32

  • 位图本质上就是一个普通的字节串,也就是 bytes 数组。可以使用getbit/setbit命令来处理这个位数组,位图的结构如下所示:
    在这里插入图片描述

  • 位图适用于一些特定的应用场景,比如用户签到次数、筛选用户、或者登录次数、疫病感染人数(14亿个位)等两个状态的。上图是表示一位用户 10 天内来网站的签到次数,1 代表签到,0 代表未签到,这样可以很轻松地统计出用户的活跃程度。相比于直接使用字符串而言,位图中的每一条记录仅占用一个 bit 位,从而大大降低了内存空间使用率。

传统的统计打卡记录:设计用户打卡表,包含(userid,status,day)等字段。

在redis可以使用string/hash类型。如:set user:ID:是否打卡 打卡状态位

  • Redis 官方也做了一个实验,他们模拟了一个拥有 1 亿 2 千 8 百万用户的系统,然后使用 Redis 的位图来统计“日均用户数量”,最终所用时间的约为 50ms,且仅仅占用 16 MB内存。
8.1 位图应用原理
  • 某网站要统计一个用户一年的签到记录,若用 sring 类型存储,则需要 365 个键值对。若使用位图存储,即操作二进制位来进行记录。用户签到就存 1,否则存 0。最后会生成 11010101… 这样的存储结果,其中每天的记录只占一位,一年就是 365 位,约为 46 个字节。如果只想统计用户签到的天数,那么统计 1 的个数即可。

位图操作的优势,相比于字符串而言,它不仅效率高,而且还非常的节省空间。

  • Redis 的位数组是自动扩展的,如果设置了某个偏移位置超出了现有的内容范围,位数组就会自动扩充。下面设置一个名为 a 的 key,我们对这个 key 进行位图操作,使得 a 的对应的 value 变为“he”。首先我们分别获取字符“h”和字符“e”的八位二进制码,如下所示:
>>> bin(ord("h"))
'0b1101000'
>>> bin(ord("e"))
'0b1100101'
  • 接下来,只要对需值为 1 的位进行操作即可。如下图所示:
    在这里插入图片描述
  • 把 h 和 e 的二进制码连接在一起,第一位的下标是 0,依次递增至 15,然后将数字为 1 的位置标记出来,得到 1/2/4/9/10/13/15,我们把这组数字称为位的“偏置数”,最后按照上述偏置数对字符 a 进行如下位图操作。注意,key 的初始二进制位全部为 0。
remote:0>setbit a 1 1
"0"
remote:0>setbit a 2 1
"0"
remote:0>setbit a 4 1
"1"
remote:0>get a
"h"
remote:0>setbit a 9 1
"0"
remote:0>setbit a 10 1
"0"
remote:0>setbit a 13 1
"1"
remote:0>setbit a 15 1
"0"
remote:0>get a
"he"
#从示例可以得出,位图操作会自动对 key 进行扩容。
  • 如果对应位的字节是不可以被打印的,那么 Redis 会以该字符的十六进制数来表示它,如下所示:
remote:0>setbit b 0 1
"0"
remote:0>setbit b 1 1
"0"
remote:0>get b
"\xc0"
8.2 位图常用命令
8.3.1 SETBIT命令
  • 用来设置或者清除某一位上的值,其返回值是原来位上存储的值。key 在初始状态下所有的位都为 0 ,语法格式如下:
SETBIT key offset value
  • 其中 offset 表示偏移量,从 0 开始。示例如下:
remote:0>set name zs
"OK"
#设置偏移量0上的值为1
remote:0>setbit name 0 1
"0"
#当对应位的字符是不可打印字符,redis会以16进制形式显示
remote:0>get name
"\xe1"
9.3.2 GETBIT命令
  • 用来获取某一位上的值。示例如下:
remote:0>getbit name 0
"1"
  • 当偏移量 offset 比字符串的长度大,或者当 key 不存在时,返回 0。
remote:0>exists mybits
"0"
remote:0>getbit mybits 200
"0"
9.3.3 BITCOUNT命令
  • 统计指定位区间上,值为 1 的个数。语法格式如下:
BITCOUNT key [start end]
  • 示例如下:
remote:0>bitcount name 0 -1
"11"
  • 通过指定的 start 和 end 参数,可以让计数只在特定的字节上进行。start 和 end 参数和 GETRANGE命令的参数类似,都可以使用负数,比如 -1 表示倒数第一个位, -2 表示倒数第二个位。
下一篇:redis学习-13- Redis 数值操作命令
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值