Redis数据结构之GEO

未完待续

1.概述

移动互联网时代LBS应用越来越多,交友软件中附近的人、外卖软件中附近的美食店铺等,那这种附近各种形形色色的地址位置选择是如何实现的?

地球上的地理位置是使用二维的经纬度表示,经度范围(-180,180],纬度范围(-90,90],只要我们确定一个点的经纬度就可以取得它在地球上的位置。

例如滴滴打车,最直观的操作就是实时记录更新各个车的位置,然后当我们要找车时,在数据库中查找距离我们(x0, y0)附近r公里范围内部的车辆,使用如下SQL即可:

select taxi from position where x0 - r < x < x0 + r and y0 - r < y < y0 + r

但是这样会有查询性能问题,如果并发高数据量大,这种查询会影响数据库性能,而且这个查询到的是一个矩形范围,而不是以点为中心r公里为半径的圆形范围。

为了解决这一问题,Redis在3.2版本之后支持了GEO这一数据结构,GEO主要用于存储地理位置信息,并对存储的信息进行操作,包括:

  • 添加地理位置的坐标
  • 获取地理位置的坐标
  • 计算两个位置之间的距离
  • 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合

2.常用命令

2.1 GEOADD

多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的key中

GEOADD key longitude latitude member [longitude latitude member ...]

经纬度可以通过百度地图坐标拾取获得:https://api.map.baidu.com/lbsapi/getpoint/index.html

例如:

127.0.0.1:6379> GEOADD city 116.515802 39.951893 "北京朝阳站" 116.385671 39.871141 "北京南站"
(integer) 1

GEO的本质是Set的子类型:

127.0.0.1:6379> type city
zset
127.0.0.1:6379> zrange city 0 -1
1) "\xe5\x8c\x97\xe4\xba\xac\xe5\x8d\x97\xe7\xab\x99"
2) "\xe5\x8c\x97\xe4\xba\xac\xe7\xab\x99"
3) "\xe5\x8c\x97\xe4\xba\xac\xe6\x9c\x9d\xe9\x98\xb3\xe7\xab\x99"
127.0.0.1:6379> 

中文乱码的解决:修改客户端参数

127.0.0.1:6379> quit
[root@localhost bin]# ./redis-cli --raw
127.0.0.1:6379> auth lzj
OK
127.0.0.1:6379> zrange city 0 -1
北京南站
北京站
北京朝阳站

2.2 GEOPOS

用于从给定的key里返回所有指定名称(member)的位置(经度和纬度),不存在的返回nil

GEOPOS key member [member ...]

127.0.0.1:6379> GEOPOS city 北京站
116.43414348363876343
39.90890963654599233
127.0.0.1:6379> GEOPOS city  北京朝阳站
116.51580065488815308
39.95189343796607062

2.3 GEODIST

返回两个给定位置之间的距离

  • m
  • km千米
  • ft英尺
  • mi英里
GEODIST key memberl member2 [m|km|ft|mi]

例:高铁站之间的距离

127.0.0.1:6379> GEODIST city 北京站 北京朝阳站 km
8.4477
127.0.0.1:6379> GEODIST city 北京南站 北京朝阳站 km
14.2804
127.0.0.1:6379> GEOADD city 117.978057 40.893571 "承德南站"
1
127.0.0.1:6379> GEODIST city 承德南站 北京朝阳站 km
162.1702

2.4 GEORADIUS

以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有位置元素,说白了就是根据半径检索附近的POI(兴趣点)

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
  • key: 存储地理位置的有序集合键名
  • longitude latitude: 中心点的经度和纬度
  • radius: 半径距离
  • m|km|ft|mi: 距离单位(米、千米、英尺、英里)
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHDIST: 在返回位置元素的同时,将位置元素与中心之间的距离也一并返回, 距离的单位和用户给定的范围单位保持一致
  • WITHHASH: 以52位有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值,这个选项主要用于底层应用或者调试,实际中的作用并不大
  • COUNT count: 限制返回结果数量
  • ASC|DESC: 按距离排序(升序/降序)
  • STORE key: 将结果存储为有序集合(存储 geohash)
  • STOREDIST key: 将结果存储为有序集合(存储距离)

例:以朝阳公园(116.486817,39.953201)为圆心,10千米为半径,搜索city中满足条件的地点

127.0.0.1:6379> GEORADIUS city 116.486817 39.953201 10 km WITHCOORD WITHDIST
北京站
6.6672
116.43414348363876343
39.90890963654599233
北京朝阳站
2.4755
116.51580065488815308
39.95189343796607062

2.5 GEORADIUSBYMEMBER

跟GEORADIUS类似

2.6 GEOHASH

返回一个或多个位置元素的GEOHASH表示,比位数众多的小数更好处理

GEOHASH算法生成的base32编码值,主要分为三步:
1.将三维的地球变为二维的坐标
2.将二维的坐标转换为一维的点块
3.最后将一维的点块转换为二进制再通过base32编码

GEOHASH key member [member ...]

127.0.0.1:6379> GEOHASH city 北京站 北京南站 北京朝阳站
wx4g190y0p0
wx4fb6m6nx0
wx4g73h0wu0

"如果文章对您有帮助,可以请作者喝杯咖啡吗?"

微信二维码

微信支付

支付宝二维码

支付宝


Redis数据结构之GEO
https://blog.liuzijian.com/post/redis-data-structure-geo.html
作者
Liu Zijian
发布于
2024年10月16日
许可协议