前言
是的,我不是标题党,我保证好哥哥们都没有用过,用过的就不是好哥哥(诶诶诶,好哥哥们轻点,别打脸)。实话说,要是我不弄 Redis 的这个专题博客,我还真不知地道有像
HyperLogLog
、Bitmaps
、Lua
等相关的功能。我相信好多好哥哥们也跟我一样,对整个 Redis 都是只会用其中的某些基础东西,你看看这不是有学到了吗。今天这个的话一样的我还是没有用过,但是我好学呀,弄它,明年面试(不是猛男我啊,我学这个可不是为了装*)的时候又可以装一波,装完就跑的那种。
概述
Redis3.2 版本提供了GEO
(地理信息定位)功能,GEO
主要用于存储地理位置信息,并对存储的信息进行操作,用于实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能,对于需要实现这些功能的开发者来说是一大福音。
命令
增加地理位置信息
Redis 提供geoadd
命令来添加或者更新地理信息位置,其中longitude
、latitude
、member
分别是该地理位置的经度、纬度、成员。添加如下图的城市经纬度
## 格式
geoadd key longitude latitude member [longitude latitude member ...]
## 添加北京,返回结果代表添加成功的个数,假如已经存在了则返回0
127.0.0.1:6379> geoadd cities:locations 116.28 39.55 beijing
(integer) 1
获取地理信息位置
## 格式 ,member 成员
geopos key member [member ...]
## 获取天津的地理位置
127.0.0.1:6379> geopos cities:locations tianjin
1) 1) "117.12000042200088501"
2) "39.0800000535766543"
获取两个地理位置的距离
Redis
提供了geodist
来获取两个地理位置的距离。其中unit
代表返回结果的单位,包含以下四种:
- m(meters)代表米。
- km(kilometers)代表公里。
- mi(miles)代表英里。
- ft(feet)代表尺。
## 格式
geodist key member1 member2 [unit]
## 计算北京到天津的距离
127.0.0.1:6379> geodist cities:locations tianjin beijing km
"89.2061"
获取指定位置范围内的地理信息位置集合
georadius
和georadiusbymember
两个命令的作用是一样的,都是以一个地 理位置为中心算出指定半径内的其他地理信息位置,不同的是georadius
命令 的中心位置给出了具体的经纬度,georadiusbymember
只需给出成员即可。其 中radiusm|km|ft|mi
是必需参数,指定了半径(带单位),这两个命令有很多 可选参数,如下:
- withcoord:返回结果中包含经纬度。
- withdist:返回结果中包含离中心节点位置的距离。
- withhash:返回结果中包含 geohash,有关 geohash 后面介绍。
- COUNT count:指定返回结果的数量。
- asc|desc:返回结果按照离中心节点的距离做升序或者降序。
- store key:将返回结果的地理位置信息保存到指定键。
- storedist key:将返回结果离中心节点的距离保存到指定键。
## 格式
georadius key longitude latitude radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
## 格式
georadiusbymember key member radiusm|km|ft|mi [withcoord] [withdist]
[withhash] [COUNT count] [asc|desc] [store key] [storedist key]
## 计算五座城市中,距离北京150公里以内的城市
127.0.0.1:6379> georadiusbymember cities:locations beijing 150 km
1) "beijing"
2) "tianjin"
3) "tangshan"
4) "baoding"
获取 GeoHash
GeoHash
GeoHash
本质上是空间索引的一种方式,其基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码。以 GeoHash 方式建立空间索引,可以提高对空间 poi 数据进行经纬度检索的效率。具体可以看Geohash 原理 使用 geohash
将二维经纬度转换为一维字符串,geohash
有如下特点:
GEO
的数据类型为zset
,Redis 将所有地理位置信息的geohash
存放在zset
中。- 字符串越长,表示的位置更精确,例如
geohash
长度为 9 时,精度在 2 米左右。如下图 - 两个字符串越相似,它们之间的距离越近,Redis 利用字符串前缀匹配算法实现相关的命令。
geohash
编码和经纬度是可以相互转换的。
## 格式
geohash key member [member ...]
## 计算北京的geohash
127.0.0.1:6379> geohash cities:locations beijing
1) "wx4ww02w070"
删除地理位置信息
GEO
没有提供删除成员的命令,但是因为GEO
的底层实现是zset
,所以 可以借用zrem
命令实现对地理位置信息的删除。
## 格式
zrem key member
127.0.0.1:6379> zrem cities:locations beijing
1
原理
增加地理位置原理
上面有说GEO
的底层数据结构是zset(sorted set)
,这个基本的数据结构不了解的话可以看Redis Sorted Set 运用场景、API 解析。先看一个zset
的新增命令zadd key score member [score member ...]
,好哥哥们发现了吗,是不是很相似。有比较杠的好哥哥就会说了,这哪里相似,GEO
明显有经纬度两个值,而zset
只有一个score
。是的,实际上这个地方是运用了一个算法那就是通过经纬度计算出对应的 52 位(bit
)的 GEOHASH
(这个其实也是一个算法,上面有提到过) 值作为元素的 Score
值。那这样是不是就和zset
一样了呢。所以其存储的原理和zset
是一样的,只是多了一个计算Score
值的过程。
geohash 原理分析
这个实际上上面已经有提到了,如果好哥哥们没有看懂那篇的话猛男我又找了一篇比较好懂的,可以看下GeoHash 核心原理解析,如果不想看的话那我总结如下(好哥哥们我都这样了你确定还不点赞加个关注吗)。 理解GeoHash
需要解决以下两个问题:
- 如何唯一表示地球上的一块空间?
- 如何将地球切分成大小近似的区块,并支持不同粒度的表示?
方案:
- 将三维地球变成二维: 地球纬度区间是[-90,90],经度区间是[-180,180]。 将它展开想象成一个很大的矩形。
- 将二维再转成一维: 通过第一步的方法,我们能够将地球的表面转换成二维空间的平面。那接下来要将二维转变成一维。如果切割二维空间,可以切割出很多正方形。如何表示这个正方形呢?最简单的方法是在平面上进行遍历。每遍历到一个点,就给它标注一个值,比如 00、01、10、11,随着二进制数字增加,相当于遍历面上不同的位置。当将空间划分为四块时候,编码的顺序分别是左下角 00,左上角 01,右下脚 10,右上角 11,也就是类似于 Z 的曲线。
- 将一维表示成二进制码存储:
Geohash
也有几种编码形式,常见的有 2 种,base 32
和base 36
。 会将落到网格中的二进制数据编码成字符串。
使用场景
这个上面已经提到了,例如附近位置、附件的人、摇一摇这类依赖于地理位置信息的功能都可以使用GEO
来实现。
总结
这一篇关于地理信息定位GEO
,没有讲的太深,这个篇幅就已经很长了。主要的一个难点就是在于GeoHash
的一个计算算法上,要搞懂这个的话好哥哥们还是要看看上面的两篇文章,当然也可以自己去搜索相关的资料,讲道理这个功能还是挺好玩的。后面有机会去踩踩坑,有熟悉的好哥哥可以把坑留着评论区。
本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞
今天的文章「进击Redis」十七、保证你没用过Redis GEO分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16693.html