1. Redis数据类型-Geospatial

Geospatial 简称GEO,翻译过来是地理空间的意思,是 Redis 3.2 版本新增一种数据类型,底层的索引结构是ZSet。主要用于存储地理位置信息,并对存储的信息进行操作。

2. 常用命令

所有命令:

命名 描述
GEOADD 将指定的地理空间位置(纬度、经度、名称)添加到指定的key
GEODIST 返回两个给定位置之间的距离
GEOHASH 返回一个或多个位置元素的 Geohash 表示
GEOPOS key里返回所有给定位置元素的位置(经度和纬度)
GEORADIUS 以给定的经纬度为中心,找出某一半径内的元素
GEORADIUS_RO GEORADIUS 命令的只读变体,只是它不支持可选的 STORESTOREDIST 参数
GEORADIUSBYMEMBER 找出位于指定范围内的元素,中心点是由给定的位置元素决定
GEORADIUSBYMEMBER_RO GEORADIUSBYMEMBER 命令的只读变体,只是它不支持可选的 STORESTOREDIST 参数
GEOSEARCHSTORE 类似于GEOSEARCH,但它将结果存储在目标键中
GEOSEARCH 扩展了GEORADIUS命令,因此除了支持在圆形区域内搜索外,还支持在矩形区域内搜索

2.1 GEOADD

GEOADD 用于将给定的空间元素(纬度、经度、名字)添加到指定的键中,这些数据会以有序集合的形式被储存。

命令语法:

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

注意事项:

  • GEOADD 命令以标准的 x,y 格式接受参数, 所以用户必须先输入经度, 然后再输入纬度。
  • GEOADD 能够记录的坐标是有限的,非常接近两极的区域是无法被索引的。

精确的坐标限制由 EPSG:900913 / EPSG:3785 / OSGEO:41001 等坐标系统定义, 具体如下:

  • 经度范围从-180度到180度。
  • 纬度范围从-85.05112878度到85.05112878度。
  • 当用户尝试输入一个超出范围的经度或者纬度时, GEOADD 命令将返回一个错误。

示例:

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.1516"
redis> GEORADIUS Sicily 15 37 100 km
1) "Catania"
redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"

2.2 GEODIST

GEODIST 命令用于返回两个给定位置之间的距离。

注意事项:

  • 如果两个位置之间的其中一个不存在, 那么命令返回空值。
  • 在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
  • 计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在, 那么命令返回空值。

命令语法:

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

参数说明:

  • member1 member2 :两个地理位置
  • [m|km|ft|mi]:距离单位,默认使用米作为单位
    • m :米,默认单位。
    • km :千米。
    • mi :英里。
    • ft :英尺。

示例:

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.1516"
redis> GEODIST Sicily Palermo Catania km
"166.2742"
redis> GEODIST Sicily Palermo Catania mi
"103.3182"
redis> GEODIST Sicily Foo Bar
(nil)

2.3 GEORADIUS

GEORADIUS 命令是用于根据给定的经纬度和半径,查询指定键中存储的地理位置信息的有序集合附近的元素。允许你根据给定的经纬度和半径来查询附近的位置信息,并可以返回丰富的结果集,包括位置的经纬度、与查询点的距离以及Geohash值等。通过合理地使用这些选项,可以轻松地实现各种基于位置的搜索和查询功能。

命令语法:

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

参数说明:

  • keyRedis中存储地理位置信息的有序集合的名称。
  • longitudelatitude:查询点的经度和纬度。
  • radius:查询半径,可以指定单位(m表示米,km表示千米,ft表示英尺,mi表示英里)。
  • WITHCOORD:返回结果中包含元素的经纬度信息。
  • WITHDIST:返回结果中包含元素与查询点的距离。
  • WITHHASH:返回结果中包含元素的Geohash值。
  • COUNT count:限制返回结果的数量。
  • ASC|DESC:按距离排序结果,默认为升序(ASC),可选降序(DESC)。
  • STORE key:将结果存储到另一个键中,而不是直接返回。
  • STOREDIST key:将结果和对应的距离存储到另一个键中,结果是一个包含两个元素的数组(成员和距离)。

示例:

# 添加 Palermo、Catania的位置信息
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
# 查询 15.37 200千米内的所有位置
redis> GEORADIUS Sicily 15 37 200 km WITHDIST
 1) "Palermo"
   2) "190.4424"
 1) "Catania"
   2) "56.4413"
redis> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
   2) 1) "13.36138933897018433"
      2) "38.11555639549629859"
2) 1) "Catania"
   2) 1) "15.08726745843887329"
      2) "37.50266842333162032"
redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
   2) "190.4424"
   3) 1) "13.36138933897018433"
      2) "38.11555639549629859"
2) 1) "Catania"
   2) "56.4413"
   3) 1) "15.08726745843887329"
      2) "37.50266842333162032"

2.4 GEOPOS

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

命令语法:

GEOPOS key member [member ...]

注意事项:

  • 因为该命令接受可变数量的位置元素作为输入, 所以即使用户只给定了一个位置元素, 命令也会返回数组回复。
  • GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。 当给定的位置元素不存在时, 对应的数组项为 nil

示例:

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "15.08726745843887329"
   2) "37.50266842333162032"
3) (nil)

2.5 GEORADIUSBYMEMBER

GEORADIUSBYMEMBERGEORADIUS 命令一样, 都可以找出位于指定范围内的元素,但是其中心点是由给定的位置元素(位置名称)决定的, 而不是使用经度和纬度来决定中心点。

基本语法:

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

示例:

redis> GEOADD Sicily 13.583333 37.316667 "Agrigento"
(integer) 1
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"

3. 应用场景

Redis 的地理空间(Geospatial)功能允许你存储地理位置信息,并进行查询操作,如计算两个地理位置之间的距离、找出给定位置附近的其他位置等。以下是一些使用 Redis 地理空间功能的用例场景和脚本代码:

3.1. 附近地点搜索

场景:在地图应用中,找出用户当前位置附近的餐厅、加油站或其他兴趣点。

命令GEORADIUSGEORADIUSBYMEMBER

# 添加地点
GEOADD places 116.397128 39.916527 "Tiananmen"
GEOADD places 116.383328 39.900000 "Forbidden City"

# 找出距离 Tiananmen 5公里内的所有地点
GEORADIUS places 116.397128 39.916527 5 km

# 找出距离 Forbidden City 5公里内的所有地点
GEORADIUSBYMEMBER places "Forbidden City" 5 km

3.2. 计算两点间距离

场景:计算两个地点之间的距离,例如用户和最近的取货点之间的距离。

命令GEODIST

# 添加地点
GEOADD delivery 116.397128 39.916527 "Warehouse A"
GEOADD delivery 116.383328 39.900000 "Warehouse B"

# 计算 Warehouse A 到 Warehouse B 的距离
GEODIST delivery "Warehouse A" "Warehouse B" km

3.3. 地点的地理排序

场景:根据地理位置对一系列地点进行排序,例如按距离用户最近的顺序显示餐厅列表。

命令GEORADIUSWITHDIST

# 添加地点
GEOADD restaurants 116.397128 39.916527 "Restaurant 1"
GEOADD restaurants 116.383328 39.900000 "Restaurant 2"
GEOADD restaurants 116.393328 39.910000 "Restaurant 3"

# 找出距离特定位置最近的餐厅并按距离排序
GEORADIUS restaurants 116.397128 39.916527 10 km WITHDIST

3.4. 地理位置的成员查询

场景:查询某个地点是否在特定区域内,例如检查用户是否在某个公园内。

命令GEORADIUSWITHIN

# 添加地点
GEOADD parks 116.397128 39.916527 "Park A"

# 检查用户是否在 Park A 内
GEORADIUS parks 116.397128 39.916527 1 km COUNT 1

3.5. 动态更新地理位置

场景:实时更新移动对象的位置,如出租车或快递车辆的位置。

命令ZADDGEORADIUS

# 更新出租车的位置
GEOADD taxis 116.387128 39.906527 "Taxi 123"

# 找出距离某个地点最近的出租车
GEORADIUS taxis 116.383328 39.900000 2 km

以上这些用例展示了 Redis 地理空间功能在不同场景下的应用,通过这些命令可以有效地处理地理位置数据和相关的查询。