Redis 命令及数据类型 -- Geo
摘要
- 本文介绍 Redis Geo 数据类型
- 本文基于
redis-7.4.7,springboot-3.5.8 - Redis官网:https://redis.io/
- Redis 命令文档:https://redis.io/docs/latest/commands/
Geo 数据类型
-
Redis Geo 是基于有序集合(
zset) 实现的地理空间操作功能,底层用geohash编码存储经纬度,核心支持 6 个基础操作 + 2 个扩展操作,兼顾精准存储、距离计算、范围筛选等核心需求,直接对接实际场景(如附近门店、同城好友)。 -
有效经度(longitude)为
-180 ~ 180,有效纬度(latitude)为-85.05112878 ~ 85.05112878。 -
Redis 内部实现中:
1 | GEO 数据 ≈ ZSET |
Geohash 是什么?
-
Geohash 是一种将二维地理坐标(经度、纬度)编码为一维字符串或整数的空间索引算法,核心目标是:
1 | 将「位置」映射为「可排序的值」 |
-
核心思想
不断对经纬度区间进行二分,并交叉编码
编码顺序:经度 → 纬度 → 经度 → 纬度 → …
1 | 每一步: |
-
Redis 内部的 Geohash 字符 =
52bit,即 经度26 bit,纬度26 bit
1 | 每个字符 = 5 bit |
Geohash 计算过程示例
1 | longitude = 116.397128 |
-
为了简化计算过程,我们这里固定一个常用精度:
- 精度选择:5 个 Geohash 字符 = 25 个 bit ⇒ 经度 13 bit,纬度 12 bit(奇数位经度)
-
逐位计算(关键过程)
1️⃣ 经度 bit(13 位)
| 位次 | 区间 | mid | 判断 | bit |
|---|---|---|---|---|
| 1 | [-180,180] | 0 | 116 ≥ 0 | 1 |
| 2 | [0,180] | 90 | 116 ≥ 90 | 1 |
| 3 | [90,180] | 135 | 116 < 135 | 0 |
| 4 | [90,135] | 112.5 | 116 ≥ 112.5 | 1 |
| 5 | [112.5,135] | 123.75 | 116 < 123.75 | 0 |
| 6 | [112.5,123.75] | 118.125 | 116 < 118.125 | 0 |
| 7 | [112.5,118.125] | 115.3125 | 116 ≥ 115.3125 | 1 |
| 8 | [115.3125,118.125] | 116.71875 | 116 < 116.71875 | 0 |
| 9 | [115.3125,116.71875] | 116.015625 | 116 ≥ 116.015625 | 1 |
| 10 | [116.015625,116.71875] | 116.3671875 | 116 ≥ 116.3671875 | 1 |
| 11 | [116.3671875,116.71875] | 116.54296875 | 116 < 116.54296875 | 0 |
| 12 | [116.3671875,116.54296875] | 116.455078125 | 116 < 116.455078125 | 0 |
| 13 | [116.3671875,116.455078125] | 116.4111328125 | 116 < 116.4111328125 | 0 |
经度 bit(13 位):
1101001011000
2️⃣ 纬度 bit(12 位)
| 位次 | 区间 | mid | 判断 | bit |
|---|---|---|---|---|
| 1 | [-90,90] | 0 | 39 ≥ 0 | 1 |
| 2 | [0,90] | 45 | 39 < 45 | 0 |
| 3 | [0,45] | 22.5 | 39 ≥ 22.5 | 1 |
| 4 | [22.5,45] | 33.75 | 39 ≥ 33.75 | 1 |
| 5 | [33.75,45] | 39.375 | 39 < 39.375 | 0 |
| 6 | [33.75,39.375] | 36.5625 | 39 ≥ 36.5625 | 1 |
| 7 | [36.5625,39.375] | 37.96875 | 39 ≥ 37.96875 | 1 |
| 8 | [37.96875,39.375] | 38.671875 | 39 ≥ 38.671875 | 1 |
| 9 | [38.671875,39.375] | 39.0234375 | 39 < 39.0234375 | 0 |
| 10 | [38.671875,39.0234375] | 38.84765625 | 39 ≥ 38.84765625 | 1 |
| 11 | [38.84765625,39.0234375] | 38.935546875 | 39 ≥ 38.935546875 | 1 |
| 12 | [38.935546875,39.0234375] | 38.9794921875 | 39 ≥ 38.9794921875 | 1 |
纬度 bit(12 位):
101101110111
-
交叉合并(最终 bit 序列)
按规则:经度 → 纬度 → 经度 → 纬度 …
1 | 经度: 1 1 0 1 0 0 1 0 1 1 0 0 0 |
-
每 5 bit → 1 个 Base32 字符
1 | # 从左到右,每 5 位一组: |
Geohash 使用的 Base32 字符集(固定,不是 RFC Base32):
1 | Index: 0 1 2 3 4 5 6 7 8 9 |
- Geohash Base32 字符集 为什么缺少
a, i, l, o- 为了避免在视觉上引起数字混淆
1
2
3
4a 容易和 4 混淆
i 容易和 1 混淆
l 容易和 1 混淆
o 容易和 0 混淆- 去掉
a, i, l, o后刚好是 32 个字符,因为 Geohash 需要 2⁵ = 32 个字符 对应 5 bit 精度
Geo 核心基础操作(必用)
1. GEOADD:添加地理位置坐标(核心写入操作)
◦ 语法:
1 | GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...] |
◦ 示例:
1 | # 给shop集合加王府井、西单2个门店的经纬度 |
◦ 关键:经纬度顺序不能反,存储后会自动给每个成员生成geohash编码。
2. GEOPOS:获取指定成员的经纬度(精准查询坐标)
◦ 语法:
1 | GEOPOS key [member [member ...]] |
◦ 示例:
1 | # 返回王府井的经纬度数组 [经度, 纬度] |
◦ 关键:返回结果与查询成员顺序一致,不存在的成员返回nil,可批量查询提升效率。
3. GEODIST:计算两个成员之间的距离(核心计算操作)
◦ 语法:
1 | GEODIST key member1 member2 [M|KM|FT|MI] |
◦ 示例:
1 | # 返回王府井和西单之间的距离,单位为米 |
◦ 关键:返回浮点型结果,成员不存在返回nil,支持跨区域距离计算(如不同城市门店)。
4. GEOHASH:获取指定成员的geohash编码(底层编码查询)
◦ 语法:
1 | GEOHASH key [member [member ...]] |
◦ 示例:
1 | # 返回王府井的geohash字符串,共11位 |
◦ 关键:geohash编码越长精度越高,Redis默认精度足够日常使用;编码相同的成员,地理位置极近,可用于快速判近。
5. GEORADIUS:按指定经纬度为中心,筛选指定范围的成员(范围查询1,按中心点坐标)
-
即将弃用,请使用
GEOSEARCH/GEOSEARCHSTORE替代
◦ 语法:
1 | GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key] |
◦ 核心可选参数:WITHDIST(返回距离)、WITHCOORD(返回经纬度)、WITHHASH(返回geohash)、COUNT n(限制返回数量)、ASC/DESC(按距离正/倒序)
◦ 示例:
1 | # 以天安门附近为中心,查5km内10个门店,按距离从近到远返回并带距离 |
6. GEORADIUSBYMEMBER:按已有成员为中心,筛选指定范围的成员(范围查询2,按已有节点,更常用)
-
即将弃用,请使用
GEOSEARCH/GEOSEARCHSTORE替代
◦ 语法:
1 | GEORADIUSBYMEMBER key member radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key] |
◦ 可选参数与GEORADIUS一致,场景更贴合实际(如查“我附近”的门店,先存自己的坐标为成员,再用此命令)
◦ 示例:
1 | # 查王府井3km内的门店,按距离排序 |
Geo 扩展操作(实战常用)
1. GEOSEARCH(Redis 6.2+ 新增,替代 GEORADIUS/GEORADIUSBYMEMBER)
◦ 优势:功能更全、语法更统一,支持两种查询模式,是未来主流用法
1 | GEOSEARCH key <FROMMEMBER member | FROMLONLAT longitude latitude> |
◦ 语法1(按坐标中心):GEOSEARCH key FROMLONLAT 经度 纬度 BYRADIUS 距离 单位 [可选参数]
1 | # 查天安门3km内的门店,按距离排序 |
◦ 语法2(按成员中心):GEOSEARCH key FROMMEMBER 中心成员 BYRADIUS 距离 单位 [可选参数]
1 | # 查王府井3km内的门店,按距离排序 |
◦ 新增特性:支持 BYBOX(按矩形范围查询),适配更多场景(如查询某片区内的门店)。
1 | # 查王府井2.0*2.0km内的门店,按距离排序,这里以 王府井 为矩形的中心,查询2.0*2.0km内的门店 |
2. GEOSEARCHSTORE(Redis 6.2+ 新增)
◦ 作用:将 GEOSEARCH 的查询结果,直接存储到指定zset中,方便后续二次处理(如分页、排序)
◦ 语法:GEOSEARCHSTORE 目标key 源key 查询条件(同GEOSEARCH)
1 | GEOSEARCHSTORE destination source |
◦ 示例:
1 | # 把王府井3km内的门店,存到near_shop集合 |
底层核心与实战注意事项
-
底层本质:所有Geo操作的key,本质都是zset,因此zset的命令(如ZREM、ZSCORE)可直接用于Geo key,例如 ZREM shop xidan 可删除西单的地理位置(Geo无单独删除命令,依赖ZREM)。
-
精度限制:经纬度支持小数点后多位,但Redis内部会做精度取舍,日常场景(如打车、门店)完全够用,无需额外处理。
-
性能优化:大范围查询(如100km以上)建议加COUNT限制返回数量;高频查询可将结果缓存到普通key,减少Geo计算开销。
-
适用场景:附近门店、同城社交、物流定位,不适用高精度场景(如军事、测绘),此类场景需用专业GIS系统。
典型实战场景示例
-
需求:搭建“附近餐饮”查询功能,支持添加餐饮坐标、查询当前位置3km内餐饮并按距离排序。
1 | # 1. 批量添加餐饮坐标 |
Geo 命令
-
SpringBoot 的
StringRedisTemplate.opsForGeo()中 Geo 数据类型 的操作方法与 Redis 原生命令的对应关系如下:
注意这里一定要用
StringRedisTemplate来操作 Geo
写入 / 删除类操作
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 添加单个坐标 | add(K key, Point point, M member) |
GEOADD key longitude latitude member |
返回 新增成员数量(已存在则返回 0) |
| 添加单个位置 | add(K key, GeoLocation<M> location) |
GEOADD key longitude latitude member |
GeoLocation 内部封装了 Point + member |
| 批量添加 | add(K key, Map<M, Point> map) |
GEOADD key lon1 lat1 member1 [lon2 lat2 member2 ...] |
推荐,一次网络 IO |
| 批量添加 | add(K key, Iterable<GeoLocation<M>> locations) |
GEOADD key lon1 lat1 member1 [lon2 lat2 member2 ...] |
与 Map 方式等价 |
| 删除成员 | remove(K key, M... members) |
ZREM key member [member ...] |
GEO 本质是 Sorted Set |
1 | Point point = new Point(longitude, latitude); |
距离 / 坐标 / 哈希查询
| 方法功能 | 方法 | Redis 原始命令 | 说明 |
|---|---|---|---|
| 两点距离 | distance(K key, m1, m2) |
GEODIST key m1 m2 |
默认单位米 |
| 指定单位距离 | distance(K key, m1, m2, metric) |
GEODIST key m1 m2 unit |
m / km / mi / ft |
| 获取 GeoHash | hash(K key, M... members) |
GEOHASH key member |
用于调试 |
| 获取坐标 | position(K key, M... members) |
GEOPOS key member |
lon / lat |
半径查询(旧接口,已不推荐)
Redis 6.2 起,官方不推荐继续使用 GEORADIUS / GEORADIUSBYMEMBER,但 Spring 仍保留接口以兼容。
-
1️⃣ 基于坐标点
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 半径查询 | radius(K key, Circle within) |
GEORADIUS key lon lat radius |
| 半径 + 参数 | radius(K key, Circle within, args) |
GEORADIUS |
-
2️⃣ 基于成员
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 半径查询 | radius(K key, member, radius) |
GEORADIUSBYMEMBER |
| 指定单位 | radius(K key, member, Distance) |
GEORADIUSBYMEMBER |
| 带参数 | radius(K key, member, Distance, args) |
GEORADIUSBYMEMBER |
搜索查询(推荐使用 GEOSEARCH)
替代 GEORADIUS / GEORADIUSBYMEMBER
-
1️⃣ 按圆形范围搜索
| 方法功能 | 方法 | Redis 原始命令 | 说明 |
|---|---|---|---|
| 圆形搜索 | search(K key, Circle within) |
GEOSEARCH |
新推荐接口 |
| 指定参考点 | search(K key, GeoReference, Distance) |
GEOSEARCH |
FROMMEMBER / FROMLONLAT |
| 带参数 | search(K key, reference, radius, args) |
GEOSEARCH |
支持排序、limit |
-
2️⃣ 按矩形范围搜索
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 矩形搜索 | search(K key, reference, BoundingBox) |
GEOSEARCH |
| 带参数 | search(K key, reference, BoundingBox, args) |
GEOSEARCH |
-
通用搜索(底层能力)
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 任意 GeoShape | search(K key, reference, GeoShape, args) |
GEOSEARCH |
1 | // 基于给定的坐标搜索 |
搜索并存储(GEOSEARCHSTORE)
这是 搜索 + 写入 的组合操作,结果会写入新的 ZSet
-
1️⃣ 圆形范围存储
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 搜索并存储 | searchAndStore(K key, destKey, Circle) |
GEOSEARCHSTORE |
| 指定参考点 | searchAndStore(K key, destKey, reference, radius) |
GEOSEARCHSTORE |
| 带参数 | searchAndStore(K key, destKey, reference, radius, args) |
GEOSEARCHSTORE |
-
2️⃣ 矩形范围存储
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 矩形存储 | searchAndStore(K key, destKey, reference, BoundingBox) |
GEOSEARCHSTORE |
| 带参数 | searchAndStore(K key, destKey, reference, BoundingBox, args) |
GEOSEARCHSTORE |
-
3️⃣ 通用 GeoShape 存储
| 方法功能 | 方法 | Redis 原始命令 |
|---|---|---|
| 通用存储 | searchAndStore(K key, destKey, reference, GeoShape, args) |
GEOSEARCHSTORE |