这篇文章主要介绍了Redis中的GEO地理位置模块怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

GEO是 Redis 在3.2版本之后新增的地理位置模块,意味可以用 Redis 来实现附近的地点功能。【相关推荐:Redis视频教程】

用数据库计算

一般的方法都是通过矩形区域来限定元素的数量,然后对区域内的元素进行全量距离计算再排序。这样可以明显减少计算量。

selectidfrompositionswherex0-r<x<x0+randy0-r<y<y0+r

以上SQL为了增加性能,需要在经纬度坐标加上双向复合索引。但是数据库查询性能毕竟有限,如果在高并发场合,这可能并不是一个很好的方案。

GEO算法

业界比较通用的地理位置距离排序算法是 GeoHash 算法,Redis 也使用 GeoHash 算法。

GeoHash 算法将 二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。当我们想要计算「附近的人时」,首先将目标位置映射到这条线上,然后在这个一维的线上获取附近的点就行了。

算法实现,它将整个地球看成一个 二维平面,然后划分成了一系列正方形的方格,就好比围棋棋盘。所有的地图元素坐标都将放置于唯一的方格中。方格越小,坐标越精确。然后对这些方格进行整数编码,越是靠近的方格编码越是接近。

编码之后,每个地图元素的坐标都将变成一个整数,通过这个整数可以还原出元素的坐标,整数越长,还原出来的坐标值的损失程度就越小。

GeoHash 算法会继续对这个整数做一次 base32 编码 (0-9,a-z 去掉 a,i,l,o 四个字母) 变成一个字符串。

在 Redis 里面,经纬度使用 52 位的整数进行编码,放进了 zset 里面,zsetvalue 是元素的 keyscoreGeoHash 的 52 位整数值。

在使用 Redis 进行 Geo 查询时,我们要时刻想到它的内部结构实际上只是一个 zset(skiplist)。通过 zsetscore 排序就可以得到坐标附近的其它元素 (实际情况要复杂一些,不过这样理解足够了),通过将 score 还原成坐标值就可以得到元素的原始坐标。

Redis GEO指令

1. 增加 geoadd

geoaddkeylongitudelatitudemember[longitudelatitudemember...]

127.0.0.1:6379>geoaddbeijing116.40385639.924043gugong(integer)1127.0.0.1:6379>geoaddbeijing116.34362039.947633dongwuyuan(integer)1127.0.0.1:6379>geoaddbeijing116.32864339.900272xizhan116.41532439.931231meishuguan116.41685239.887607tiantan(integer)3

删除用 zset 的 zrem 即可

2. 距离 geodist

geodistkeymember1member2[unit]

127.0.0.1:6379>geodistbeijinggugongxizhankm"6.9402"127.0.0.1:6379>geodistbeijinggugongdongwuyuan#默认单位m"5768.5737"127.0.0.1:6379>geodistbeijingxizhanxizhan"0.0000"

距离单位可以是 m、km、ml、ft,分别代表米、千米、英里和尺。

3. 位置 geopos

geoposkeymember[member...]

127.0.0.1:6379>geoposbeijinggugong1)1)"116.4038559794426"2)"39.92404192186725"127.0.0.1:6379>geoposbeijingtiantanxizhan1)1)"116.41685396432877"2)"39.887607839922914"2)1)"116.32864147424698"2)"39.900271306834973"

4. hash值 geohash

geohashkeymember[member...]

127.0.0.1:6379>geohashbeijinggugong1)"wx4g0gfwqk0"

经纬度字符串编码是 base32 编码,可以通过 http://geohash.org/wx4g0gfwqk0 直接查找经纬度

5. 附近地点 georadiusbymember

1、查询 ireader 范围 20 公里以内最多 3 个元素按距离正排,它不会排除自身(倒排使用用 desc

127.0.0.1:6379>georadiusbymembercompanyireader20kmcount3asc1)"ireader"2)"juejin"3)"meituan"

2、三个可选参数 withcoord withdist withhash 用来携带附加参数, withdist 很有用,它可以用来显示距离

georadiusbymemberkeymemberradiusm|km|ft|mi[WITHCOORD][WITHDIST][WITHHASH][COUNTcount][ASC|DES]

127.0.0.1:6379>georadiusbymemberbeijinggugong5kmwithcoordwithdistwithhashcount3asc1)1)"gugong"2)"0.0000"3)(integer)40698855689324434)1)"116.4038559794426"2)"39.92404192186725"2)1)"meishuguan"2)"1.2634"3)(integer)40698857103904354)1)"116.41532510519028"2)"39.93123039107514"3)1)"tiantan"2)"4.2014"3)(integer)40698853985025574)1)"116.41685396432877"2)"39.887607839922914"

3、根据坐标值来查询附近的元素

georadiuskeylongitudelatituderadiusm|km|ft|mi[WITHCOORD][WITHDIST][WITHHASH][COUNTcount][ASC|DES]

127.0.0.1:6379>georadiusbeijing116.38388239.9220615kmwithcoordwithdistwithhashcount3asc1)1)"gugong"2)"1.7180"3)(integer)40698855689324434)1)"116.4038559794426"2)"39.92404192186725"2)1)"meishuguan"2)"2.8693"3)(integer)40698857103904354)1)"116.41532510519028"2)"39.93123039107514"3)1)"dongwuyuan"2)"4.4588"3)(integer)40698798364196884)1)"116.34361892938614"2)"39.94763257169722"注意事项

实际应用中数据可能会有百万千万条,我们知道 Redis Geo 将全部放在一个 zset 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。

所以,这里建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。

如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset 集合的大小。

感谢你能够认真阅读完这篇文章,希望小编分享的“Redis中的GEO地理位置模块怎么用”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!