redis除了五种基本数据类型外还有Bitmap,HyperLogLog,GEO,Stream这些扩展类型。使用扩展类型,可以高效的处理一些特定需求。
Bitmap
Bitmap也叫位图它只有0和1两个值,底层基于String类型,由于String 类型会保存为二进制的字节数组,所以redis 把字节数组的每个 bit 位利用起来,构成 bit 数组以达到节省内存空间的目的。
基于Bitmap特性,通常用其实现签到,展示用户在线状态等业务。
以签到为例,简单介绍下bitmap用法
id为1的用户2021年8月1日签到成功,由于offset从0起始,所以日期减1
setbit user1:sign:202108 0 1
查看是否签到成功
getbit user1:sign:202108 0
统计该用户本月签到次数
bitcount user1:sign:202108
bitmap还提供了bitop名利对多个bitmap做聚合统计
其语法为bitop and(交集)、or(并集)、not(非)、xor(异或) 聚合后的key key1 key2 ...
下面以统计连续签到两天的用户为例
20210801这天用户id为1的用户签到
setbit sign:20210801 1 1
20210802这天用户id为1和2的用户签到
setbit sign:20210802 1 1
setbit sign:20210802 2 1
使用bitop取交集
bitop and merage:sign sign:20210801 sign:20210802
使用bitcount验证结果
bitcount merage:sign
HyperLogLog
HyperLogLog 是一种用于统计基数的数据集合类型。每个 HyperLogLog 占用12 K 内存,可以计算接近 2^64 个元素的基数。相较于hash,set类型来说占用内存小,但有HyperLogLog是概率统计标准误差率为0.81%
根据基数统计特性,HyperLogLog一般用于统计网页uv,独立ip访问量等操作,其使用方式比较简单
页面page1的uv,访问用户id为1
pfadd page1:uv 1
页面page1的uv总数
pfcount page1:uv
HyperLogLog还可以对多个key取并集操作,例如
pfadd page1:uv 1 2 3
pfadd page2:uv 1 4
对page1:uv,page2:uv 取并集
pfmerge merge:uv page1:uv page2:uv
pfcount验证
pfcount merge:uv
GEO
GEO主要用于存储地理位置信息,使用GEO可以实现附近的人,附近的餐馆等需求,其底层基于zset,新增查询时使用GeoHash算法对经纬度进行打分计算
GeoHash算法主要思想是把地球看成一个平面,对平面进行多次二分切割,最终会切割成一个一个小正方形,在切割过程中处于左区间的坐标编码为0,右区间编码为1。举个简单的例子,杭州东站坐标为120.21861,30.297024,现在进行三次切割
经度最小值 | 经度最大值 | 经度中间值 | 经度区间 | 编码 | |
第一次 | -180 | 180 | 0 | [0,180) | 1 |
第二次 | 0 | 180 | 90 | [90,180) | 1 |
第三次 | 90 | 180 | 135 | [90,135) | 0 |
维度最小值 | 维度最大值 | 维度中间值 | 维度区间 | 编码 | |
第一次 | -180 | 180 | 0 | [0,180) | 1 |
第二次 | 0 | 180 | 90 | [90,180) | 0 |
第三次 | 0 | 90 | 45 | [0,45) | 0 |
切割完成后得到经度编码110,维度编码100,将经度编码放偶数位,维度编码放奇数位得到最终编码110100,这个值就是zset的权重,保存和查询时都通过该方法计算得到附近的人
GEO简单使用如下
添加id为1用户坐标
geoadd nearby:location 120.21861 30.297024 1
添加id为2用户坐标
geoadd nearby:location 120.172616 30.302013 2
添加id为3用户坐标
geoadd nearby:location 120.116275 30.286546 3
添加id为4用户坐标
geoadd nearby:location 118.089697 30.598895 4
获取id为2用户坐标
geopos nearby:location 2
计算id为1和2用户之间距离
geodist nearby:location 1 2 km
查询指定地址附近50km用户根据距离正序排序,取前2位
georadius nearby:location 120.111111 30.28666 50 km asc count 2
查询id为2的用户100km内存在的用户根据距离正序排序
georadiusbymember nearby:location 2 100 km asc
Stream
redis为消息队列设计的数据类型,个人认为消息队列还是应该用rocketmq,kafka这种,使用redis无法保证消息可靠性。如果对消息不敏感又懒得搭mq可以用redis