Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:
(1) Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。
(2) Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量
Aredis:0>setbit unique:users:20230101 1 1
"0"
Aredis:0>setbit unique:users:20230101 6 1
"0"
Aredis:0>setbit unique:users:20230101 11 1
"0"
Aredis:0>setbit unique:users:20230101 15 1
"0"
Aredis:0>setbit unique:users:20230101 19 1
"0"
**注:**
很多应用的用户id以一个指定的数字开头,直接将用户id和Bitmaps的偏移量对应势必会造成一定的浪费,通常做法是每次 setbit 操作时将用户id减去这个指定的数字
在第一次初始化Bitmaps时,加入偏移量非常大,那么整个初始化的过程执行会比较慢,可能会造成Redis阻塞
# 返回0表示没有访问过
Aredis:0>getbit unique:users:20230101 8
"0"
Aredis:0>getbit unique:users:20230101 6
"1"
Aredis:0>getbit unique:users:20230101 11
"1"
Aredis:0>getbit unique:users:20230101 11100
"0"
Aredis:0>getbit unique:users:20230101 100
"0"
Aredis:0>bitcount unique:users:20230101
"5"
start和end代表起始和结束字节数,下面操作计算用户id在第1到3个字节之间的访问用户数
Aredis:0>bitcount unique:users:20230101 1 3
"3"
注意:setbit设置或清除的是bit位置,而bitcount计算的是byte位置
Aredis:0>bitcount unique:users:20230301
"0"
Aredis:0>bitcount unique:users:20230101
"5"
Aredis:0>bitcount unique:users:20230101 1 3
"3"
Aredis:0>setbit unique:users:20221220 1 1
"0"
Aredis:0>setbit unique:users:20221220 4 1
"0"
Aredis:0>setbit unique:users:20221220 9 1
"0"
Aredis:0>setbit unique:users:20221220 11 1
"0"
Aredis:0>bitop and unique:users:and:22_23 unique:users:20221220 unique:users:20230101
"3"
计算出任意一天都访问的用户数量,可以使用or求并集
Aredis:0>bitop or unique:users:or:22_23 unique:users:20221220 unique:users:20230101
"3"
Aredis:0>bitcount unique:users:or:22_23
"7"
假设1亿用户,每天独立访问量50000000,如果每天用set类型和bitmaps类型分别存储可以得到
数据类型 | 每个id占用空间 | 需要存储的用户量 | 全部内存量 |
---|---|---|---|
set类型 | 64位 | 50000000 | 64 / 8 * 50000000 = 400Mb |
Bitmap类型 | 1位 | 100000000 | 1 / 8 * 100000000 = 12.5Mb |
这种情况下使用Bitmaps能节省很多内存空间。
但是如果每天独立访问量很少,只有100000,那么两这个对比使用Bitmaps就不合适了
数据类型 | 每个id占用空间 | 需要存储的用户量 | 全部内存量 |
---|---|---|---|
set类型 | 64位 | 100000 | 64 / 8 * 100000 = 800kb |
Bitmap类型 | 1位 | 100000000 | 1 / 8 * 100000000 = 12.5Mb |
求集合中不重复元素的问题称为基数问题
Redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或体积非常大时,计算基数所需的空间总时固定的、并且时很小的
但是,因为HyperLogLog只会根据输入元素来计算基数,而不会存储输入元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素
数据集中不重复的元素
添加指定元素到HyperLogLog中
Aredis:0>pfadd h1 "redis"
"1"
Aredis:0>pfadd h1 "mysql"
"1"
Aredis:0>pfadd h1 "redis"
"0"
将所有的元素添加到指定的HyperLogLog数据结构中,如果执行命令后HLL估计的近似基数发生变化,则返回1, 否则 返回 0
Aredis:0>pfadd h2 "redis"
"1"
Aredis:0>pfadd h2 "mongo"
"1"
Aredis:0>pfcount h1 h2
"3"
Aredis:0>PFMERGE H3 h2 h1
"OK"
Aredis:0>PFCOUNT H3
"3"
GEO, Geographic,地理信息的缩写。该类型就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,距离查询,范围查询,经纬度Hash常见操作
Aredis:0>geoadd china:city 121.47 31.23 shanghai
"1"
Aredis:0>geoadd china:city 106.50 39.53 chongqing 116.38 39.90 北京
"2"
两极无法直接添加,一般会下载城市数据,通过脚本一次性导入。有效的精度从-180到180,维度从-85.05112878 度到 85.05112878 度
已经添加的数据无法再次往里面添加
Aredis:0>geopos china:city shanghai
1) 1) "121.47000163793563843"
2) "31.22999903975783553
Aredis:0>geodist china:city shanghai 北京 km
"1068.1535"
# 单位:
# m 表示单位为米[默认值]。
# km 表示单位为千米。
# mi 表示单位为英里。
# ft 表示单位为英尺。
# 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位
Aredis:0>georadius china:city 110 30 3000 km
1) "chongqing"
2) "shanghai"
3) "北京"