Geospatial
一、类型概述
Geospatial 是 Redis 在 3.2 版本中新增的一种数据类型。它并不是一种全新的底层数据结构,而是基于 Sorted Set(有序集合) 实现的功能扩展。
它专门用于存储和操作地理位置信息,允许你存储经纬度坐标,并基于这些坐标进行复杂的计算,例如:
- 计算两个位置之间的距离。
- 查找某个指定点半径内的所有其他位置。
- 获取位置的 Geohash 值。
二、基本方法
[ ]是可选的意思
1. 添加方法
geoadd key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]
bash
[NX|XX] [CH]的描述详见ZSet longitude经度 latitude纬度
有效的经度范围是从-180 到 180 度。
有效的纬度范围是从-85.05112878 到 85.05112878 度。
127.0.0.1:6379> geoadd people 100.45 10.04 p1 155.20 11.34 p2 80.55 40.99 p3 105.49 33.50 p4
(integer) 4
2. 查找方法 geopos key [member [member ...]]
bash
127.0.0.1:6379> geopos people p1 p2 p3 p4
1) 1) "100.45000165700912"
2) "10.03999882812709"
2) 1) "155.19999772310257"
2) "11.339999012165372"
3) 1) "80.55000096559525"
2) "40.99000116237913"
4) 1) "105.490001142025"
2) "33.499998990657744"
3. 返回两个位置之间的距离geodist key member1 member2 [M|KM|FT|MI]
[M|KM|FT|MI]表示单位
bash
127.0.0.1:6379> geodist people p1 p2 km
"5976.9722"
4. GEOSEARCH key <FROMMEMBER member | FROMLONLAT longitude latitude> <BYRADIUS radius unit | BYBOX width height unit> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
注意要求(Redis 6.2+)
作用: 用于在一个地理空间索引(即一个特殊的 Sorted Set)中搜索位于指定形状(圆形或矩形)和中心点范围内的所有位置元素。
-
参数解析
-
- 指定要搜索的 Key (
key
)
- 指定要搜索的 Key (
这是你之前使用
GEOADD
添加了地理位置数据的那个键。
*
2. 指定搜索的中心点 (<FROMMEMBER | FROMLONLAT>
) 你必须从这两个选项中二选一,以确定搜索的圆心或矩形的中心。-
FROMMEMBER member
使用指定
member
(即已存在于 key 中的地点名称)的坐标作为中心点。示例:
FROMMEMBER "Beijing"
表示以"北京"这个地点的坐标为中心进行搜索。 -
FROMLONLAT longitude latitude
使用你自己提供的经纬度坐标作为中心点。
示例:
FROMLONLAT 116.40 39.90
表示以经度116.40,纬度39.90这个点为中心进行搜索。 -
- 指定搜索区域的形状 (
<BYRADIUS | BYBOX>
) 你必须从这两个选项中二选一,以确定搜索区域的边界。
-
BYRADIUS radius unit
在一个圆形区域内进行搜索。
radius
: 半径数值。unit
: 单位,可以是m
(米),km
(千米),mi
(英里),ft
(英尺)。示例:
BYRADIUS 100 km
表示在半径为100公里的圆形区域内搜索。 -
BYBOX width height unit
在一个轴对齐的矩形(即南北/东西方向的矩形,不是旋转的)区域内进行搜索。
width
: 矩形从中心向东和 西延伸的距离(即宽度是2 * width
)。height
: 矩形从中心向北和 南延伸的距离(即高度是2 * height
)。unit
: 单位,同上。示例:
BYBOX 50 30 km
表示搜索一个东西宽100公里(中心点左右各50公里)、南北长60公里(中心点上下各30公里)的矩形区域。
- 指定搜索区域的形状 (
-
- 指定返回的附加信息 (
[WITH*]
选项)
这些是可选的,用于控制返回结果的丰富程度。
-
WITHCOORD
在结果中一并返回匹配项的经纬度坐标。
-
WITHDIST
在结果中一并返回匹配项与中心点的距离。
-
WITHHASH
在结果中一并返回匹配项原始的 Geohash 整数值(52位整数)。这通常用于调试,一般业务场景用不到。
- 指定返回的附加信息 (
-
-
限制和排序结果 (
[COUNT] [ASC|DESC]
)这些也是可选的,用于对结果集进行筛选和排序。
COUNT count
限制返回结果的数量。即使范围内有100个地点,
COUNT 5
也只会返回5个。注意: 如果不指定排序,
COUNT
的行为在 Redis 7.0 前后有变化。在 7.0 中,默认不应用任何限制,除非显式指定。为安全起见,最好与ASC
/DESC
联用。-
ASC
将结果按距离从近到远排序。
-
DESC
将结果按距离从远到近排序。
-
-
bash
127.0.0.1:6379> geosearch people frommember p1 byradius 5000 km asc count 3 withdist
1) 1) "p1"
2) "0.0000"
2) 1) "p4"
2) "2659.7315"
3) 1) "p3"
2) "3958.1901"
三、内部实现
Geospatial 的内部实现巧妙地利用了 Sorted Set 和 Geohash 算法。
-
数据结构:
- 当你使用
GEOADD
添加一个地理位置时,Redis 会将其存储在一个 Sorted Set 中。 - Sorted Set 的
member
: 就是你添加的地理位置名称(如 "Beijing")。 - Sorted Set 的
score
: 是一个 52 位的整数,这个整数是由 Geohash 算法计算出来的。
- 当你使用
-
Geohash 算法:
- Geohash 的核心思想是将地球表面递归地划分为网格,并为每个网格分配一个唯一的编码。
- 算法将经纬度坐标转换成一个 Base32 编码的字符串。Redis 内部将这个字符串转换成一个 52 位的整数值作为 Sorted Set 的分数(score)。
四、应用场景
-
附近的人 / 附近的商家
- 这是最典型的应用。在社交、外卖、团购等 App 中,这是核心功能。
- 实现 : 将用户/商家的坐标
GEOADD
到集合中。当用户想查找附近的人或商家时,使用GEOSEARCH ... FROMMEMBER ... BYRADIUS ...
命令即可快速获取列表。
-
共享单车 / 网约车
- 用于查找用户附近的空闲单车或车辆。
- 实现: 实时更新所有单车的位置到 Redis 中。用户打开 App 时,直接查询用户所在位置半径内的所有单车。
-
地理位置围栏
- 判断一个点(如车辆、快递员)是否进入或离开某个特定区域。
- 实现 : 可以定期将设备的坐标与预设的围栏区域(使用
GEOSEARCH ... BYBOX ...
)进行比对,如果发现设备出现在围栏内,则触发相应操作。
-
物流与配送路径优化
- 虽然复杂的路径规划需要专门的 GIS 系统,但 Redis GEO 可以快速筛选出配送点附近的仓库或中转站,作为路径规划的初步输入。
-
旅行规划
- 在某个旅游城市,查找景点附近的所有酒店或餐厅。