最近在公司接收到一个需求,用户定位后,返回用户所在位置附近的人。
第一版
通过埋点或者登陆定位时的经纬度,存到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 用于存储指定的地理空间位置,可以将一个或多个经度(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 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]
参数说明:
georadiusbymember 实例:
这样就查出这个用户附近100公里的用户了。
原文:https://www.cnblogs.com/GreenForestQuan/p/14310434.html