我们在篇 深刻理解高性能Redis的本质 的时候就介绍过Redis的几种基本数据结构,它是基于不同业务场景而设计的:
Location Based Services,记作 LBS,基于用户的地理位置数据定位展开的服务,广泛应用与地图类(百度地图、高德地图)、电商团购类(美团、饿了么)软件。它常见的使用场景有:
有没有感觉很熟悉,当然了,在我们的身边到处都是这样的应用场景。
Redis 的 GEO 特性在 Redis 3.2 版本就有了, 这个功能主要是用于存储用户地理位置信息,并对这些信息进行操作。
GEO 的数据结构总共有六个命令,我们一个个来介绍 :
Redis 提供了 GEOADD key longitude latitude member 命令,将一组经纬度信息和对应的所属对象的信息 记录到 GEO 类型的集合中,指令如下
GEOADD key longitude latitude member [longitude latitude member ...]
longitude latitude member
分别指给定的空间元素:维度、精度、名称
,这些数据会以有序集合的形式存储在给定的键里面。
我们举个例子,如果你在地图上查找美食,那应该会出现一堆餐饮店铺和坐标位置,那他们的空间信息存储可能是这样的。
redis> GEOADD food:location 115.775632 39.483256 "东北饺子馆" 114.081569 39.692756 "兰州拉面"
(integer) 2
提供对应的键和位置名称,返回相应的经纬度信息。
GEOPOS key member [member ...]
按照上面的例子,我要获取对应的美食店位置坐标信息如下:
redis> GEOPOS food:location 东北饺子馆 兰州拉面 NonExisting
"115.775632 39.483256"
"114.081569 39.692756"
很多时候,我们要导航去一个地方就会用到这类需求。打开百度或者高德地图,起始位置就定位用户当前位置,目的地定位为搜索到的地址,比如上面的 东北饺子馆。
这时候地图软件需要计算出两个坐标之间的举例,来推荐用户是飞机高铁、开车、还是步行。那么获取给定两个位置之间的距离就变得非常重要,GEODIST就是用来解决这个问题的。
GEODIST key member1 member2 [unit]
上述指令可以返回两个给定位置之间的距离,unit是距离单位,可选项,默认为m,枚举如下:
需要注意的是如果两个位置之间的其中一个不存在, 那么会返回空值。下面代码计算出 东北饺子馆 和 兰州拉面 店铺之间的距离,大概是6.1公里。
redis> GEODIST food:location 东北饺子馆 兰州拉面
"6184.15156"
很多种应用场景是我登录了外卖APP,也确定了我自己所在的位置(即已确知经纬),需要获取一定距离范围内(比如10公里),所有的餐饮店。
这时候就使用到了 GEO 提供的 GEORADIUS指令了:根据输入的经纬度,查找以这个经纬度为中心的一定距离内的其他位置信息。
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count]
key longitude latitude
: 是前置条件,给定的经纬度信息,以及我要搜索的keyradius
:距离半径,指的搜索的范围m|km|ft|mi
: 为给定的距离单位,有 米、千米、英尺、英里 4种[WITHCOORD] [WITHDIST] [WITHHASH]
: 为返回的信息类型
ASC|DESC
:可选参数,按照距离升序或者降序排列,即 由近到远(asc) 还是 由远到近(desc)COUNT count
:取数数量,避免获取到太多的信息,返回太多信息所以如果需要获取 距离本人位置10公里半径内由近到远的美食店排序,按km单位计算,返回值带上距离信息,并只取前100个的信息,代码如下:
redis> GEORADIUS food:location 115.791331 39.5120003 10 km WITHDIST ASC COUNT 100
"东北饺子馆" 3.3421
"兰州拉面" 9.4571
下图的绿色区域在固定半径(红圈)中搜索到了特定的几个目标位置:1、2、5、9、10。
与 GEORADIUS
的区别是 GEORADIUSBYMEMBER
的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样,通过传入经度和纬度来决定中心点。
所以如下,已知兰州拉面和东北饺子馆的距离是6.1公里,根据兰州拉面获取10公里范围内的距离的美食店,可以获取到东北饺子馆和自己的位置:
redis> GEORADIUSBYMEMBER food:location "兰州拉面" 100 km WITHDIST
"东北饺子馆" 6.09127
"兰州拉面" 0
redis> ZREM food:location "兰州拉面"
(integer) 1