Redis三种特殊数据类型——geospatial
关于地理位置相关的,例如:
- 好友定位,附近的人,打车距离计算等。
查询经纬度网站:http://www.jsons.cn/lngcodeinfo/
相关命令
增:geoadd
# GEOADD key longitude latitude member [longitude latitude member ...]
# 地球两极无法直接添加,我们一般会下载城市数据,直接通过程序一次性导入
# 有效的经度从-180°到180°
# 有效的纬度从-85.05112878°到85.05112878°
# 在redis中,如果经纬度超出上述范围,则会报错
127.0.0.1:6379> GEOADD China:city 116.40 39.90 beijing 121.47 31.23 shanghai 106.50 29.53 chongqing 114.05 22.54 shenzhen
(integer) 4
127.0.0.1:6379> GEOADD China:city 120.16 30.28 hangzhou 108.96 34.26 xian
(integer) 2
查:
GEOPOS:获取指定元素的经纬度
127.0.0.1:6379> GEOPOS China:city beijing
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS China:city beijing chongqing
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
GEODIST:查询两个经纬度之间的距离
127.0.0.1:6379> GEODIST China:city beijing shanghai
"1067378.7564"
# 如果有一个元素的地理位置不存在,则返回nil
127.0.0.1:6379> GEODIST China:city beijing shang
(nil)
127.0.0.1:6379> GEODIST China:city beijing shanghai km
"1067.3788"
单位:
- mi:英里
- ft:英尺
不加参数默认为米(m)
应用场景:
-
附近的人
获得所有附近的人的定位,通过半径来进行查询
# GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST k
127.0.0.1:6379> GEORADIUS China:city 108 35 1000 km
1) "xian"
2) "chongqing"
3) "beijing"
127.0.0.1:6379> GEORADIUS China:city 108 35 800 km
1) "xian"
2) "chongqing"
127.0.0.1:6379> GEORADIUS China:city 108 35 800 km withcoord # 查出对应元素具体的经纬度的值
1) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
2) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS China:city 108 35 800 km withcoord count 3 # 限制查询数量
1) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
2) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS China:city 108 35 800 km withcoord count 1 # 类似于MySQL的limit
1) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
GEORADIUSBYMEMBER
127.0.0.1:6379> GEORADIUSBYMEMBER China:city beijing 1000 km
1) "beijing"
2) "xian"
GEO底层的实现原理:就是zset(有序集合),插入每个元素的时候,标一个序号,所以我们可以用zset命令来操作geo。
127.0.0.1:6379> ZRANGE China:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> ZREM China:city beijing xian
(integer) 2
127.0.0.1:6379> ZRANGE China:city 0 -1
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
redis三种特殊类型——Hyperloglog
什么是基数?
基数:一个数据集中不重复的元素。
A: {1, 3, 5, 7, 9, 7}
B: {1, 3, 5, 7, 9}
基数(不重复的元素)=5,可以接受误差
Hyperloglog简介
Redis tribution 2.8.9版本就更新了Hyperloglog数据结构。
Redis Hyperloglog 是基数统计的算法。
场景:
统计网页的UV(即Unique Visitor,不重复访客,访问量,一个人访问某个网站多次,但是还是只计算为一次)。
-
传统方式
- 使用set来保存用户的id,然后就可以统计set中元素数量作为标准来判断(在高并发的场景可能会有误差)。如果网站访问量大,用户id比较长,而且用户比较多,那么就增加网络资源的消耗,且会降低查询效率。
- 我们的目的是为了计数,而不是保存用户id
-
Hyperloglog
- 占用内存是固定的,2^64不同元素的基数,只需要12kb内存。
- 官方说法,使用该方法的错误率是0.81%,对于统计UV任务来说,可以忽略不计。
因此,从内存角度来比较的话,Hyperloglog就是首选。
127.0.0.1:6379> PFADD mykey a b c d e f g
(integer) 1
127.0.0.1:6379> PFCOUNT mykey
(integer) 7
# ===========
# PFMERGE destkey sourcekey [sourcekey ...]
# 从源(sourcekey)key合并数据到目标(destkey)key中
127.0.0.1:6379> PFMERGE mykey2 mykey
OK
127.0.0.1:6379> PFCOUNT mykey2
(integer) 12
127.0.0.1:6379> PFCOUNT mykey
(integer) 7
# 可以看到,destkey可以是已存在的key,也可以是不存在的key,最后把合并的结果保存到destkey中
127.0.0.1:6379> PFMERGE mykey3 mykey2 mykey
OK
总结:
如果允许容错,那么一定可以使用Hyperloglog。
如果不允许容错,就使用set或者自己的数据类型即可。
Redis三种特殊数据类型——Bitmaps
位存储
场景
-
统计用户信息,活跃,不活跃
-
登录,未登录
-
打卡,未打卡
传统做法:设计一个数据库表,包含以下字段user_id, status, day,最后按年或者按月统计。
总结:只要是只有两个状态的(0,1),都可以使用Bitmaps
Bitmaps(位图),也是一种数据结构,都是操作二进制位来进行记录,就只有0和1两个状态。
365天的打卡记录,只需要存365个0或1,一个0或1的大小是1bit,8bit=1bytes,总共只需46个字节左右。
记录7天的打卡记录,0:未打卡,1:已打卡
127.0.0.1:6379> SETBIT status 0 1
(integer) 0
127.0.0.1:6379> SETBIT status 1 1
(integer) 0
127.0.0.1:6379> SETBIT status 2 0
(integer) 0
127.0.0.1:6379> SETBIT status 3 1
(integer) 0
127.0.0.1:6379> SETBIT status 4 0
(integer) 0
127.0.0.1:6379> SETBIT status 5 1
(integer) 0
127.0.0.1:6379> SETBIT status 6 1
(integer) 0
查看某一天的打卡记录
127.0.0.1:6379> GETBIT status 1
(integer) 1
127.0.0.1:6379> GETBIT status 2
(integer) 0
统计操作(7天的已打卡记录):
127.0.0.1:6379> bitcount status
(integer) 5
# BITCOUNT key [start end]
# start:设置位索引起始位置(包含该位置计数),第一个位置以0开始,start参数需和end参数同时设置才合法。
# end: 设置位索引结束位置(包含该位置计数),end参数需和start参数同时设置才合法。
注意:BITCOUNT 的 start 和 end 参数的索引意义是以 1 byte 作为单位,如
bitcount mykey 0 0
命令表示 mykey 的字符串的第一个字节中比特位 1 的个数(即字符串第一个字符的比特位为 1 的个数)。
设置了day 1到day 24的打卡状态,day 3, 5, 9, 13, 14为0,其他为1
127.0.0.1:6379> BITCOUNT status 0 0
(integer) 5
127.0.0.1:6379> BITCOUNT status 0 1
(integer) 10
127.0.0.1:6379> BITCOUNT status 0 2
(integer) 18
127.0.0.1:6379> BITCOUNT status 0 3
(integer) 19
127.0.0.1:6379> BITCOUNT status 1 3
(integer) 14
127.0.0.1:6379> BITCOUNT status 2 3
(integer) 9
127.0.0.1:6379> BITCOUNT status 3 3
(integer) 1