redis---地理模块Geo模块

redis在3.2版本以后增加了地理位置Geo模块,意味着我们可以使用redis来实现类似摩拜单车的“附近的Mobike”,微信的“附近的人”这样的功能。

丢弃redis

再介绍新模块之前,可以先思考下其他的方法实现这个问题,我们可以通过数据库保存位置信息,从而实现这项功能。

地图元素采用经纬度的表示,经度范围[-180,180],纬度范围[-90,90],纬度正负以赤道为界限,北正南负,经度正负以英国格林威治天文台为界,东正西负。

当两个的元素的距离不是很远时,可以同勾股定理计算出距离,可是当距离较远时,需要考虑地球时椭圆形的,需要按照一定的系数加权后再进行求和。

对于较少的数据的尚可,当坐标点较多时,数据库存取的压力也会提升,可以将坐标点使用复合索引提升查询效率,但是数据库查询性能毕竟有限,使用数据库显然不是很好的方案。

redis中的GeoHash

业界比较通用的地理位置距离排序算法是GeoHash算法。该算法是将二维的经纬度数据映射到一维的整数,这样所有的元素都可以挂载到一条线上,距离靠近的二维坐标映射到一维都的点之间距离也会很接近。当我们想要计算附近的人时,首先将目标位置映射到这条线上,然后在这个一维的线上获取附近的点就可以了。

如何映射?可以将整个地球看成一个二维平面,然后划分成一系列的正方形的方格
在这里插入图片描述
如图所示,一个正方形的豆腐块,二刀下去均分分成四个小正方形,这个四个小正方形分别标记00,01,10,11,然后对每一个小正方形都采用相同的方法继续切割下去,正方形会越来越小,二进制的整数也就会越来越长,精确度就会越来越高。
以上的可以称作二刀法或者二分切割法,编码之后,每个地图的元素的坐标都将变成一个整数,通过这个整数可以还原出元素的坐标,整数越长,还原出来的坐标值的精度损失度就越小。

GeoHash算法会继续对这个整数进行一次base32编码变成一个字符串,在redis里,经纬度使用52位的整数进行编码,放进zset里面,zset的value时元素的key,score是GeoHash的52位整数值,zset的score虽然是浮点数,但是对于52的整数值可以无损存储。

GeoHash基本用法

redis提供的Geo指令只有6个:
增加:geoadd
距离:geodist
获取元素位置:geopos
获取元素的hash值:geohash
附近的位置:georadiusbymember/georadius

geoadd : (纬度、经度、名称)三元组
127.0.0.1:6379> geoadd company 116.48105 39.996794 juejin
(integer) 1
127.0.0.1:6379> geoadd company 116.514203 39.905409 ireader
(integer) 1
127.0.0.1:6379> geoadd company 116.489033 40.007669 meituan
(integer) 1
127.0.0.1:6379> geoadd company 116.562108 39.787602 jd 116.334255 40.027400           xiaomi
(integer) 2...
geodist : 计算两个元素之间的距离
// 例如,计算集合company中juejin和ireader两个元素之间的距离,单位为km
// 其中,距离单位可以是m、km、ml、ft,分别代表米、千米、英里和尺
127.0.0.1:6379> geodist company juejin ireader km
"10.5501"
127.0.0.1:6379> geodist company juejin meituan km
"1.3878"
 127.0.0.1:6379> geodist company juejin jd km
 "24.2739"
 127.0.0.1:6379> geodist company juejin xiaomi km
 "12.9606"
 127.0.0.1:6379> geodist company juejin juejin km
  "0.0000"...
geopos : 获取集合中任意元素的经纬度坐标,可以一次获取多个
// 获取company集合中juejin元素的经纬度坐标
127.0.0.1:6379> geopos company juejin
1) 1) "116.48104995489120483"
   2) "39.99679348858259686"
127.0.0.1:6379> geopos company ireader
1) 1) "116.5142020583152771"
   2) "39.90540918662494363"
127.0.0.1:6379> geopos company juejin ireader  // 同时获取多个元素的经纬度坐标
1) 1) "116.48104995489120483"
   2) "39.99679348858259686"
2) 1) "116.5142020583152771"
   2) "39.90540918662494363"...
geohash : 获取元素经纬度坐标经过geohash算法生成的base32编码值
127.0.0.1:6379> geohash company ireader
1) "wx4g52e1ce0"
127.0.0.1:6379> geohash company juejin
1) "wx4gd94yjn0"
georadiusbymember : 查询指定元素附近的其它元素
# 根据元素查找附近的元素
# 范围 20 公里以内最多 3 个元素按距离正排,它不会排除自身
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 asc
1) "ireader"
2) "juejin"
3) "meituan"
# 范围 20 公里以内最多 3 个元素按距离倒排
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 desc
1) "jd"
2) "meituan"
3) "juejin"
# 三个可选参数 withcoord withdist withhash 用来携带附加参数
# withdist 很有用,它可以用来显示距离
127.0.0.1:6379> georadiusbymember company ireader 20 km withcoord withdist   withhash count 3 asc
1) 1) "ireader"
   2) "0.0000"
   3) (integer) 4069886008361398
   4) 1) "116.5142020583152771"
      2) "39.90540918662494363"
2) 1) "juejin"
   2) "10.5501"
   3) (integer) 4069887154388167
   4) 1) "116.48104995489120483"
      2) "39.99679348858259686"
3) 1) "meituan"
   2) "11.5748"
   3) (integer) 4069887179083478
   4) 1) "116.48903220891952515"
      2) "40.00766997707732031"...
georadius根据坐标点查找附近位置的元素
127.0.0.1:6379> georadius company 116.514202 39.905409 20 km withdist count 3 asc
1) 1) "ireader"
   2) "0.0000"
2) 1) "juejin"
   2) "10.5501"
3) 1) "meituan"
   2) "11.5748"...
Redis Geo使用时的注意事项

在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用 Redis 的 Geo 数据结构,它们将全部放在一个 zset 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。
所以,这里建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。
如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset 集合的大小。(注意:zset集合大小,进行合适地切分)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值