前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >redis位图-bitmap

redis位图-bitmap

原创
作者头像
cuiyi
修改2023-01-05 08:52:54
1.2K0
修改2023-01-05 08:52:54
举报

定义

见名知义,位映射,其实就是string类型的bit数组,并不是redis的基本数据类型,而是在string的基础上做的扩展,支持对位进行操作。

作用

精准的基数计数,既可以不保存统计对象,也可以只保存统计对象的integer类型的id。一个bit就可以做一次计数或表示一个对象,比set更节省空间。

如:统计一段时间内的用户行为,如签到、访问、点赞等;或者对大量数据作去重处理,如40亿个QQ号去重。使用bitmap时不再把redis用作缓存,而是用作db。效率高尤其是数据量大时节省空间。

基本操作

  1. setbit: 设置位的值为0或1,格式是:setbit key offset bit。设置成功后,返回offset上原来的值。 直接操作相应offset,所以时间复杂度是O(1)。
  2. getbit: 获取位的值,在key不存在、位不在key的内存空间或位上的值是0时,都返回0。 格式是:getbit key offset。 直接操作相应offset,所以时间复杂度是O(1)。
  3. bitcount: 计算汉明重量。统计指定范围内的值是1的位数,默认统计整个key。如果key不存在,返回0。主要用于统计触发相应事件的次数。 格式是:bitcount key [start,[end]]。start,end用作闭区间,且指的是字节而不是位,1byte=8bit。可以是负数,-1是最后一个字节,-2是倒数第二个字节,以此类推。 要依次查看区间内的每个位置,所以时间复杂度是O(n)。
  4. bitpos: 在key中查找第一次出现指定bit的偏移量。一般情况下,找到就返回对应的offset,如果没找到或key不存在,返回-1。但有特殊情况! 格式是:bitpos key bit [start,[end]]。区间的使用同bitcount。 如果bit是0,查找行为会有点特殊:如果未指定区间,或只指定了start,如果找不到0,会最最后一位补0,然后返回该位置对应的offset。即,在未指定闭区间的情况下,如果找不到0,会出现补0的情况。 要依次查看区间内的每个位置,所以时间复杂度是O(n)。
  5. bitop:略
  6. string的所有指令:因为bitmap不是基本数据类型,底层是string。

内存分配

  1. 以字节为最小单位进行分配
  2. 使用setbit时,如果key不存在,会分配一个长度包含offset的内存空间。
  3. 使用setbit时,如果offset超出当前内存空间,进行扩容。
  4. 因为bitmap底层使用string实现,其最大内存和string相同,都是512M。也就是最大只能分配512M的内存,对应的offset是(2^32)-1。

大内存分配会造成redis的卡顿!!

使用strlen查看bitmap的内存空间长度,返回的单位是字节。

初始化

填充0的初始化:

  1. 使用setbit时,如果key不存在,会初始化一个长度是n字节且包含offset的内存空间,所有bit位使用0填充。
  2. 使用setbit时,如果offset超出现有内存空间的长度,会以字节基本长度扩容空间保证包含offset,新扩容的空间使用0填充。

填充1的初始化:

使用string来初始化bitmap,关键环节就是把需要的字节序列通过ascii转换成对应的字符串,然后使用set指令把key的值设置为该字符串即可。

步骤如下:

  1. 把需要的bitmap需要以8位为一组进行划分,即按字节划分。
  2. 把每组转换为十进制,查看该十进制对应的ascii字符
  3. 从左到右拼接每组的字符为字符串,使用set指令把key的值设置为该字符串
  4. 使用getbit对设置后的key进行验证。

对于ascii码小于32或大于126的分组,可以尝试合并3个分组为一组,使用utf8码表。查utf8码表时,需要把二进制转换为十六进制。

代码语言:shell
复制
set bt1 '18'
# 得到的bitmap就是:00110001 00111000
set bt2 "你"
# 得到的bitmap就是:11100100 10111101 10100000
# 十六进制是:e4bda0

bitmap和string的异同

  1. bitmap不是基本的数据类型,是基于string实现的。
  2. 两者的指令是互相通用的,即可以使用string的指令set/get操作bitmap数据,也可以使用bitmap的指令getbit/setbit操作string数据。
  3. 可以使用string来初始化bitmap。

注意事项

  1. 偏移量计算是从左到右,而不是按照二进制的右为低位左为高位的方式。
  2. 内存的分配以字节位最小单位,即每次最少分配8位,内存空间的位数始终是8的倍数。
  3. bitmap和string的指令是互通的。
  4. offset的取值范围是[0,2^32)。
  5. bit只能是0或1,否则会报错。
  6. 如果key存在且不是string,报错。

使用场景

  1. n亿用户7天签到
  2. n亿用户年度在线状态
  3. 40亿QQ去重

参考推荐

http://redisdoc.com/bitmap/index.html

https://zhuanlan.zhihu.com/p/401726844

https://juejin.cn/post/7074747080492711943

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 作用
  • 基本操作
  • 内存分配
  • 初始化
    • 填充0的初始化:
      • 填充1的初始化:
      • bitmap和string的异同
      • 注意事项
      • 使用场景
      • 参考推荐
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档