在Redis中,在有序集合以及GeoHash的基础上实现了Geo类型表示地理空间信息。GeoHash是将经纬度进行编码,使二维信息变为一维信息的一种算法。下面我们就来介绍Redis中Geo类型相关的命令。

GEOADD

GEOADD命令用于向Geo类型中添加一个或多个坐标元素,并返回新添加元素个数。若元素已存在(以member参数指定的元素名称作为唯一性判断),则返回值将不包括该元素,但会更新其值。

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

在添加时,其经纬度必须符合以下条件:

  • -180 <= longitude <= 180
  • -85.05112878 <= latitude <= 85.05112878

示例

redis> GEOADD buildings 121.5056 0 ShanghaiTower
(integer) 1
redis> GEOPOS buildings ShanghaiTower
1) 1) "121.50559991598129272"
   2) "0.00000126736058093"
redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
# ShanghaiTower已经存在,返回值将不包括它,但会更新其值
(integer) 1
redis> GEOPOS buildings ShanghaiTower
1) 1) "121.50559991598129272"
   2) "31.23349948967888423"
# 不合法的坐标值
redis> GEOADD buildings 1000 500 Unknown
(error) ERR invalid longitude,latitude pair 1000.000000,500.000000

GEODIST

GEODIST命令用于获取两个由GEOADD添加的元素的距离,并表示为参数所指定的距离单位。当其中一个不存在或两个元素都不存在的情况下,将返回nil

GEODIST key member1 member2 [m|km|ft|mi]

GEODIST命令可使用参数设置其距离的单位,允许的值为:

  • m: 米
  • km: 千米
  • ft: 英尺
  • mi: 英里

在未设置的情况下,默认使用米作为单位。

示例

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
(integer) 2
redis> GEODIST buildings ShanghaiTower JinganTemple
"5842.1340"
redis> GEODIST buildings ShanghaiTower JinganTemple km
"5.8421"
redis> GEODIST buildings ShanghaiTower JinganTemple ft
"19167.1062"
redis> GEODIST buildings ShanghaiTower JinganTemple mi
"3.6301"
# 不存在的元素
redis> GEODIST buildings ShanghaiTower NoExists
(nil)

GEOHASH

GEOHASH命令用于获取一个或多个由GEOADD添加元素对应的GeoHash值,并以数组的形式返回。当其中某个元素不存在时,对应的位置将返回nil

GEOHASH key member [member ...]

命令返回以11个字符表示的GeoHash字符串值,可以通过http://geohash.org/<geohash-string>查询对应的地理位置。关于GeoHash的具体信息,可参考GeoHash - Wikipedia

示例

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
(integer) 2
redis> GEOHASH buildings ShanghaiTower
1) "wtw3svvsmd0"
redis> GEOHASH buildings ShanghaiTower JinganTemple NoExists
1) "wtw3svvsmd0"
2) "wtw3es1f0d0"
3) (nil) # 不存在

GEOPOS

GEOPOS命令用于获取一个或多个由GEOADD添加元素的坐标,并以(经度,纬度)形式的二维数组返回。当其中某个元素不存在时,对应的位置将返回nil

GEOPOS key member [member ...]

示例

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
(integer) 2
redis> GEOPOS buildings ShanghaiTower
1) 1) "121.50559991598129272"
   2) "31.23349948967888423"
# 获取多个
redis> GEOPOS buildings ShanghaiTower JinganTemple NoExists
1) 1) "121.50559991598129272"
   2) "31.23349948967888423"
2) 1) "121.44529849290847778"
   2) "31.22350001470528724"
3) (nil) # 不存在

GEORADIUS

GEORADIUS命令用于获取以指定坐标位置为中心范围内小于指定距离的位置,其返回的结果需要为GEOADD命令添加的元素。GEORADIUS命令需要指定的参数依次为键名、中心点的经度、中心点的纬度、范围半径以及范围半径的单位。与GEODIST支持的单位相同,GEORADIUS也支持米、千米、英尺、英里四种距离单位。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

GEORADIUS命令支持使用下面三个参数获取除元素名称外的信息:

  • WITHCOORD: 返回经纬度坐标。
  • WITHDIST: 返回距离中心点的距离。
  • WITHHASH: 返回GeoHash对应的整数值。

以上三个参数可以根据需要任意使用,也可以进行组合使用。当使用一个以上上述参数时,将会以下面的顺序在数组中返回:

  1. 距离中心点的距离。
  2. GeoHash值。
  3. 经纬度坐标

GEORADIUS支持通过COUNT参数指定返回的个数,以及使用ASCDESC指定返回的顺序。当使用ASC时,将以距离由近到远的顺序返回,而使用DESC时将以距离由远到近的顺序返回,在未指定默认情况下,返回结果将以从近到远的顺序排列。

另外,GEORADIUS命令还支持使用STORESTOREDIST参数将结果保存至一个有序集合中,二者的区别为STORE保存的是GeoHash值,而STOREDIST保存的是指定单位下的距离。

示例

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
(integer) 2
redis> GEORADIUS buildings 121.4800 31.2300 5 km
1) "ShanghaiTower"
2) "JinganTemple"
# 使用WITHCOORD、WITHDIST以及WITHHASH参数
redis> GEORADIUS buildings 121.4800 31.2300 5 km WITHCOORD WITHDIST WITHHASH
1) 1) "ShanghaiTower"
   2) "2.4656" # dist
   3) (integer) 4054803507567030 # hash
   4) 1) "121.50559991598129272" # coord
      2) "31.23349948967888423"
2) 1) "JinganTemple"
   2) "3.3788"
   3) (integer) 4054756202296433
   4) 1) "121.44529849290847778"
      2) "31.22350001470528724"
# 指定顺序
redis> GEORADIUS buildings 121.4800 31.2300 5 km DESC
1) "JinganTemple"
2) "ShanghaiTower"

将结果保存至指定有序集合中:

# STORE
redis> GEORADIUS buildings 121.4800 31.2300 5 km STORE zset-1
(integer) 2
redis> ZRANGEBYSCORE zset-1 -inf +inf WITHSCORES
1) "JinganTemple"
2) "4054756202296433"
3) "ShanghaiTower"
4) "4054803507567030"
# STOREDIST
redis> GEORADIUS buildings 121.4800 31.2300 5 km STOREDIST zset-2
(integer) 2
redis> ZRANGEBYSCORE zset-2 -inf +inf WITHSCORES
1) "ShanghaiTower"
2) "2.4656495023008533"
3) "JinganTemple"
4) "3.3787870481515605"

GEORADIUSBYMEMBER

GEORADIUSBYMEMBER命令与GEORADIUS命令相似,二者不同之处在于GEORADIUSBYMEMBER命令以一个存在的元素作为中心,而非指定中心的坐标。

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

对于GEORADIUSBYMEMBER的参数,可参考GEORADIUS的介绍。

示例

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower 121.4453 31.2235 JinganTemple
(integer) 2
redis> GEORADIUSBYMEMBRE buildings ShanghaiTower 10 km
1) "ShanghaiTower"
2) "JinganTemple"

删除Geo类型元素

Geo类型没有类似于其它类型删除元素的GEODEL命令,但由于Geo类型是基于有序集合实现的,所以可以使用ZREM命令移除其元素。

redis> GEOADD buildings 121.5056 31.2335 ShanghaiTower
(integer) 1
redis> GEOPOS buildings ShanghaiTower
1) 1) "121.50559991598129272"
   2) "31.23349948967888423"
redis> ZREM buildings ShanghaiTower
(integer) 1
# 删除后使用GEOPOS获取不到该元素
redis> GEOPOS buildings ShanghaiTower
(nil) 

命令扩展

通过使用Geo类型的相关命令,可以轻松地实现地理位置相关的需求,例如附近热门景点、外卖点餐筛选等。

例如GEORADIUS命令的示例所示,假定获取到当前的坐标为东经121.4800度,北纬31.2300度,只需要执行GEORADIUS tourist-spots 121.4800 31.2300 5 km WITHDIST WITHCOORD即可获取到附近5公里内的景区坐标以及距离。

参考资料