geospatial(地理位置)
微信中朋友的定位,附近的人,打车距离计算,这些都是怎么实现的呢?
Redis的Geo 在Redis3.2版本就推出来了,这个功能可以推算地理位置的信息,比如说两地之间的距离,方圆几里的人。
可以查询一些测试数据:城市地理位置经度纬度查询http://www.jsons.cn/lngcode/
geoadd 添加地理位置
# 规则:两极无法之间添加,一般会下载城市数据之间通过Python程序导入
# 参数 key 值(纬度 经度 名称)
# 有效的经度从-180度到180度。
# 有效的纬度从-85.05112878度到85.05112878度。
# 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 127.47 31.23 shanghai
(integer) 1
geopos
获得当前定位:一定是一个坐标值。
# 获取指定城市的经度和纬度
127.0.0.1:6379> geopos china:city beijing shanghai
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "127.47000128030776978"
2) "31.22999903975783553"
geodist
两人之间的距离
单位:
- m 表示单位米
- km 表示单位千米
- mi 表示单位英里
- ft 表示单位英尺
127.0.0.1:6379> geodist china:city beijing shanghai # 查看上海到北京的直线距离
"1388236.3971"
127.0.0.1:6379> geodist china:city beijing shanghai km # 单位千米
"1388.2364"
georadius 以给定的经纬度为中心,找出某一半径内的元素
我附近的人(获得所有附近的人的地址,定位)通过半径来查询,获得指定数量的人
所有的数据都应该录入:china:city才会让结果更加清晰。
127.0.0.1:6379> georadius china:city 110 30 2000 km # 以110,30这个经纬度为中心,寻找方圆1000km内的城市
1) "shanghai"
2) "beijing"
127.0.0.1:6379> georadius china:city 110 30 2000 km withdist # 显示到中间距离的位置
1) 1) "shanghai"
2) "1676.1046"
2) 1) "beijing"
2) "1245.2858"
127.0.0.1:6379> georadius china:city 110 30 2000 km withcoord # 显示他人的定位信息
1) 1) "shanghai"
2) 1) "127.47000128030776978"
2) "31.22999903975783553"
2) 1) "beijing"
2) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> georadius china:city 110 30 2000 km count 1 # 筛选出指定个数的用户
1) "beijing"
127.0.0.1:6379> georadius china:city 110 30 2000 km count 2
1) "beijing"
2) "shanghai"
georadiusbymember
# 找出位于指定元素周围的其他元素
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
127.0.0.1:6379> georadiusbymember china:city beijing 2000 km
1) "shanghai"
2) "beijing"
geohash 返回一个或多个位置元素的 Geohash 表示。很少使用
该命令将返回11个字符的Geohash字符串
# 将二维的经纬度转换为一维的字符串,如果两个字符串越相似则两个位置越接近
127.0.0.1:6379> geohash china:city beijing shanghai
1) "wx4fbxxfke0"
2) "wvd9sthzfm0"
GEO底层的实现原理其实就是zset,我们可以使用zset命令来操作geo。
127.0.0.1:6379> zrange china:city 0 -1 # 查看地图中全部元素
1) "shanghai"
2) "beijing"
127.0.0.1:6379> zrem china:city beijing # 移除指定元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "shanghai"
hyperloglog(基数)
什么是基数?
A{1,3,5,7,8,7} B{1,3,5,7,8}
基数(不重复的元素)= 5,可以接受误差
简介
Redis2.8.9版本就更新了Hyperloglog数据结构
Redis Hyperloglog是用来做基数统计的算法!
**优点:**占用的内存是固定的,2^64不同的元素的计数,只需要费12kb的内存。如果要从内存角度来比较的话Hyperloglog就是首选。
网页的UV(页面访问量,一个人访问一个网站多次,但是还是算作一个人!)
传统的方式,使用set保存用户的id,id一样就会被覆盖掉,然后就可以统计set中的元素数量作为标准判断。这种方式如果保存大量的id,就会比较麻烦,占用大量内存。我们的目的是为了计数 ,而不是保存用户id。
0.81%的错误率,在统计UV任务中是可以忽略不计的。
测试使用
127.0.0.1:6379> pfadd mykey a b c d e f g h i # 创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey # 统计 mykey中元素的基数数量
(integer) 9
127.0.0.1:6379> pfadd mykey2 j k i a b z o # 创建第二组元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2 # 统计 mykey2中元素的基数数量
(integer) 7
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 # 合并两组mykey1 和 mykey2 -》mykey3 并集
OK
127.0.0.1:6379> pfcount mykey3 # 查看并集的数量
(integer) 13
注:
如果允许容错,那么一定可以使用hyperloglog。
如果不允许容错,就使用set 或者 自己的数据类型即可。
bitmap(位图)
位存储
统计用户信息,活跃,不活跃。登录,未登录。打卡,365打卡,userid status day(比较麻烦)。两个状态的都可以使用bitmap。
bitmaps 位图,是一种数据结构。都是操作二进制位来进行记录,就只有0和1两个状态。
使用bitmaps记录 周一到周日的打卡
周一:1:打卡 周二:0:未打卡 周三:1:打卡 周四:1:打卡
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
查看某一天是否有打卡
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 6
(integer) 0
统计操作,统计打卡的天数
127.0.0.1:6379> bitcount sign # 统计这周的打开记录,就可以看到是否有全勤
(integer) 3
少年易老学难成,一寸光阴不可轻