文章目录
- 前言
- Bitmap概述
- Bitmap命令介绍
- 使用场景
- 结尾
前言
- Redis除了常见的五种数据类型之外,其实还有一些少见的数据结构,如Geo,HyperLogLog,Bitmap等。虽然它们少见,但是作用却不容小觑。本文将介绍Bitmap数据类型的语法和使用场景。
- 下文将介绍bitmap的使用指令,以及其应用场景。
Bitmap概述
- 在开发中,我们常常需要存放一些布尔类型的数据,比如我们的上班打卡记录,游戏签到记录等等。假设一个公司工作签到打卡的场景,一个员工今年第1,2,3天都工作了,需要对1,2,3做记录,如果对这三个整型数使用unsigned int来记录的话,那么需要3*4=12个字节,也就是96个bit的存储空间。而一个员工要这样记录一整年的数据,公司又不止一个员工,那么这个打卡功能就将耗费大量空间。
- 为了节省空间,Redis提供了Bitmap,也就是位图这种数据结构。所谓位图,其实就是一个bit数组,对于一年上班打卡的记录,只需要提供一个365位的bit数组,如果第一天工作了,那就将第一位bit的0改为1即可。这样一来,一个人一年的打卡记录,只需要365bit位就可以记录完成了。位图按位来存储,大大节约了空间,其存储上限为2^32。
Bitmap命令介绍
-
bitmap设置某一位的值: SETBIT key offset value
# 字母a的ASCII码是97,二进制就是01100001,一个字节 八个比特 # 字母b的ASCII码是98,二进制就是01100010 # 所以存入a只需要将0,6,7位设为1即可 # 接着存入b就需要将10,14,15位设为1。 setbit word 0 1 setbit word 6 1 setbit word 7 1 setbit word 10 1 setbit word 14 1 setbit word 15 1 # 除此之外,可以之间用字符串填充位的值 set word ab # 这个指令等价于上面的setbit
-
获取bitmap中的数据,使用单个位操作获取位的值: getbit key offset
getbit word 0 1 getbit word 1 1
-
统计bitmap指定位区间上,值为 1 的个数: bitcount key [start end]
bitcount word # 统计key为word的位图中有多少个1 bitcount word 0 1 # 前两个字符中有几个1
-
返回bitmap中第一个值为bit的二进制位的位置,可以指定范围: bitpos key bit [start end]
bitpos word 1 # 返回第一个为1的位 bitpos word 0 0 1 # 返回前两个字符中第一个为0的位
-
对一个或多个保存二进制位的字符串 key 进行位元操作(and,or,not,xor),并将结果保存到 destkey 上: BITOP operation destkey key [key …]
bitop not new_word word # 对key为word的位图取反后存入new_word之中
使用场景
- 需求:40亿个QQ号,限制1G的内存,如何对这些QQ号进行去重。
- 实现方案:通过分析需求,有1G内存的限制,所以可以使用位图来节省空间。使用位图的话,一个qq号,即一个数字只需要占用一个bit(将这个bit设置为1),那么40亿个数字也就只需要400000000/8/1024/1024=476M,满足要求。
- 代码实现:
public class RedisBitmap { private static final String QQ_NUMBER = "QQ"; /** * 将qq号码存入位图中 * 即将位图对应qq号码的bit设为1 * @param key * @param qq_number * @param jedis */ public static void saveQQNumber(String key, long qq_number, Jedis jedis){ jedis.setbit(key,qq_number,true); } /** * 获取bitmap中1的数量即可得到去重后的qq号数量 * @param key * @param jedis */ public static Long getCount(String key, Jedis jedis){ return jedis.bitcount(key); } }
结尾
- bitmap常用于上面提及的去重,上班打卡,签到记录功能,使用bitmap可以减少很多不必要的存储空间。所以当出现类似的场景时,就好好使用它吧。