Redis计算地理位置距离-GeoHash Redis GEO
最近在公司接收到一个需求,用户定位后,返回用户所在位置附近的人。
第一版
通过埋点或者登陆定位时的经纬度,存到mysql数据库中。通过sql查询返回对应的附近人的数据。
遇到了问题如下:
1.用户经纬度表更新太过频繁。导致mysql连接资源长期占用。
2.通过sql计算出附近的人,损耗mysql运算资源,虽然sql能在1秒内返回。
3.测试反馈的切换定位后,暂无数据。新用户注册,暂无数据
因为发现以上问题,我们调整了我们技术的方案:
Redis 在 3.2 版本以后增加了地理位置 GEO 模块。
地图元素的位置数据使用二维的经纬度表示,经度范围 (-180, 180],纬度范围 (-90, 90],纬度正负以赤道为界,北正南负,经度正负以本初子午线 (英国格林尼治天文台) 为 界,东正西负。比如广州的办公室经纬度(113.380627,23.132107)都是正数,因为中国位于东北半球。
当两个元素的距离不是很远时,可以直接使用勾股定理就能算得元素之间的距离。我们平时使用的「附近的人」的功能,元素距离都不是很大,勾股定理算距离足矣。不过需要注意的是,经纬度坐标的密度不一样 (经度总共 360 度,纬度总共 180 度)
有效经度为-180 ~ 180度。
有效纬度为-85.05112878 ~ 85.05112878度。
勾股定律计算平方差时之后再求和时,需要按一定的系数比加权求和。
现在,如果要计算「附近的人」,也就是给定一个元素的坐标,然后计算这个坐标附近的其它元素,按照距离进行排序,该如何下手?
如果现在元素的经纬度坐标使用关系数据库 (元素 id, 经度 x, 纬度 y) 存储,你该如何计算?
GeoHash 算法
Redis 的 GEO 特性将在 Redis 3.2 版本释出, 这个功能可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作
将指定的地理空间项目(纬度,经度,名称)添加到指定的键。数据作为排序集存储到密钥中,使得可以使用GEORADIUS或GEORADIUSBYMEMBER命令使用半径查询稍后检索项目。
注意:没有GEODEL命令,可以使用ZREM来删除元素。地理索引结构只是一个排序集。
Redis GEO实现主要包含了以下两项技术:
1、使用geohash保存地理位置的坐标。
2、使用有序集合(zset)保存地理位置的集合。
- geoadd:添加地理位置的坐标。
- geopos:获取地理位置的坐标。
- geodist:计算两个位置之间的距离。
- georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
- geohash:返回一个或多个位置对象的 geohash 值。
geoadd
geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。
geoadd 语法格式如下:
GEOADD key longitude latitude member [longitude latitude member ...]
geoadd dg:erp:chart:total:user_geo 116.48105 39.996794 38888888
以下我将用户的经纬度转换成Redis Geo
批量处理如下:
georadius 、georadiusbymember
georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
georadiusbymember 和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。
georadius 与 georadiusbymember 语法格式如下:
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
参数说明:
- m :米,默认单位。
- km :千米。
- mi :英里。
- ft :英尺。
- WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
- WITHCOORD: 将位置元素的经度和维度也一并返回。
- WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
- COUNT 限定返回的记录数。
- ASC: 查找结果根据距离从近到远排序。
- DESC: 查找结果根据从远到近排序。
georadiusbymember 实例:
实例
这样就查出这个用户附近100公里的用户了。