全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-12 10 分钟 ✍️ juanwangdev

地理空间

Redis GEO(Geographic)是Redis 3.2引入的地理位置数据结构,支持存储坐标、计算距离、查找附近地点等地理计算功能。

GEO原理

底层实现

Bash
GEO基于有序集合(ZSet)实现:
- 经纬度转换为GeoHash值
- GeoHash作为ZSet的score
- 地点名称作为ZSet的member
- 利用ZSet的范围查询能力

GeoHash编码

Bash
GeoHash原理:
- 将经纬度编码为一维字符串
- 经度范围:-180到180
- 纬度范围:-90到90
- 交替编码经纬度得到二进制串
- 转换为base32字符串

特点:
- 相邻地点GeoHash前缀相似
- 前缀匹配表示地理距离相近
- 支持范围查询附近地点

GeoHash精度

Bash
GeoHash长度与精度对应:
1位:约5000km
2位:约1250km
3位:约156km
4位:约39km
5位:约4.9km
6位:约1.2km
7位:约152m
8位:约38m
9位:约4.8m

Redis使用52位精度(约0.1mm误差)

GEO命令

GEOADD添加地理位置

Bash
# 基本语法
GEOADD key longitude latitude member [longitude latitude member ...]

# 添加单个地点
GEOADD locations 116.404 39.915 "北京"

# 添加多个地点
GEOADD locations 121.474 31.230 "上海"
GEOADD locations 113.264 23.129 "广州"
GEOADD locations 114.057 22.543 "深圳"

# 批量添加
GEOADD locations 116.404 39.915 "北京" 121.474 31.230 "上海" 113.264 23.129 "广州"

GEOPOS获取坐标

Bash
# 获取单个地点坐标
GEOPOS locations "北京"
# 返回:
# 1) 1) "116.403999477"
#    2) "39.914999802"

# 获取多个地点坐标
GEOPOS locations "北京" "上海"
# 返回两组坐标

GEODIST计算距离

Bash
# 基本语法
GEODIST key member1 member2 [unit]

# 计算两点距离(默认米)
GEODIST locations "北京" "上海"
# 返回: "1067378.83"(约1067公里)

# 指定单位
# m: 米
# km: 千米
# mi: 英里
# ft: 英尺

GEODIST locations "北京" "上海" km
# 返回: "1067.37883"

GEORADIUS查询附近地点(已弃用)

Bash
# Redis 6.2已弃用,建议使用GEOSEARCH
GEORADIUS locations 116.404 39.915 500 km WITHDIST

GEOSEARCH查询附近地点(推荐)

Bash
# 基本语法(Redis 6.2+)
GEOSEARCH key [FROMMEMBER member | FROMLONLAT longitude latitude]
  [BYRADIUS radius unit | BYBOX width height unit]
  [WITHCOORD | WITHDIST | WITHHASH]
  [COUNT count [ANY]]
  [ASC | DESC]

# 从坐标查询500km范围内的地点
GEOSEARCH locations FROMLONLAT 116.404 39.915 BYRADIUS 500 km WITHDIST
# 返回附近地点及距离

# 从地点查询附近
GEOSEARCH locations FROMMEMBER "北京" BYRADIUS 500 km WITHDIST

# 按距离排序
GEOSEARCH locations FROMMEMBER "北京" BYRADIUS 500 km WITHDIST ASC

# 限制返回数量
GEOSEARCH locations FROMMEMBER "北京" BYRADIUS 500 km COUNT 10

# 矩形范围查询
GEOSEARCH locations FROMLONLAT 116 39 BYBOX 200 200 km WITHDIST

GEOHASH获取GeoHash值

Bash
# 获取地点的GeoHash值
GEOHASH locations "北京"
# 返回: "wx4g0b5"

# 获取多个地点的GeoHash
GEOHASH locations "北京" "上海"

命令速查表

命令说明示例
GEOADD添加地理位置GEOADD k lon lat m
GEOPOS获取坐标GEOPOS k m
GEODIST计算距离GEODIST k m1 m2 km
GEOSEARCH查询附近GEOSEARCH k ...
GEOHASH获取GeoHashGEOHASH k m

应用场景

1. 附近的人/好友

Bash
# 存储用户位置
GEOADD user:locations 116.404 39.915 "user:1000"
GEOADD user:locations 116.405 39.916 "user:1001"
GEOADD user:locations 116.406 39.917 "user:1002"

# 查询5km内的用户
GEOSEARCH user:locations FROMMEMBER "user:1000" BYRADIUS 5 km WITHDIST COUNT 20

# 返回附近用户列表及距离

2. 附近门店/商家

Bash
# 存储门店位置
GEOADD store:locations 116.404 39.915 "store:A001"
GEOADD store:locations 116.405 39.916 "store:A002"

# 用户当前位置查询附近门店
user_lon = 116.403
user_lat = 39.914
GEOSEARCH store:locations FROMLONLAT user_lon user_lat BYRADIUS 3 km WITHDIST ASC COUNT 10

3. 打车/配送范围

Bash
# 存储司机位置
GEOADD driver:locations 116.404 39.915 "driver:001"

# 乘客查询附近司机
GEOSEARCH driver:locations FROMLONLAT 116.403 39.914 BYRADIUS 5 km WITHDIST ASC

# 配送范围查询
GEOSEARCH delivery:locations FROMMEMBER "配送点1" BYRADIUS 10 km

4. 地理围栏

Bash
# 检查是否在范围内
# 场馆范围:中心点100米内
venue_lon = 116.404
venue_lat = 39.915

# 用户进入场馆范围
user_lon = 116.4041
user_lat = 39.9151

# 计算距离判断
distance = GEODIST venue:user venue_center user_location m
if distance < 100:
    # 用户在场馆内

5. 路线规划辅助

Bash
# 存储路线上的关键点
GEOADD route:001 116.404 39.915 "point:1"
GEOADD route:001 116.405 39.916 "point:2"

# 计算路线总距离
distance1 = GEODIST route:001 "point:1" "point:2" km
distance2 = GEODIST route:001 "point:2" "point:3" km
total = distance1 + distance2

精度与误差

坐标精度

Bash
Redis GEO有效范围:
经度:-180到180
纬度:-85.05112878到85.05112878

超出范围会报错:
GEOADD locations 190 90 "invalid"
# 错误:经度超出范围

距离计算误差

text
使用Haversine公式计算距离:
- 基于地球椭球模型
- 理论误差约0.5%
- 实际应用误差可接受

对于短距离:
- 几百米范围内误差很小
- 长距离可能有几十米误差

GeoHash边界问题

text
GeoHash边界:
- 相邻格子GeoHash前缀可能不同
- 需要查询周围格子补充结果

解决方案:
- 搜索时扩大范围
- 使用多个中心点查询

性能优化

数据量控制

text
# 单个GEO集合控制数据量
# 建议不超过10万条

# 大数据量分片
GEOADD locations:beijing ...  # 北京区域
GEOADD locations:shanghai ... # 上海区域

查询优化

text
# 使用COUNT限制返回数量
GEOSEARCH locations ... COUNT 100

# 按距离排序,限制数量
GEOSEARCH locations ... ASC COUNT 20

# 避免查询过大范围
# 范围越大,计算量越大

定期清理

text
# 清理过期数据
# 离线用户位置定期删除
ZREM user:locations "user:offline"

# 或使用过期时间
SET user:location:1000:expire timestamp

底层ZSet操作

直接操作底层ZSet

text
# GEO数据底层是ZSet
# 可使用ZSet命令

# 查看地点数量
ZCARD locations

# 查看所有地点
ZRANGE locations 0 -1

# 删除地点
ZREM locations "北京"

# 获取GeoHash(score)
ZSCORE locations "北京"

注意事项

text
- GEO命令更方便,推荐使用
- ZSet命令可用于批量操作
- score是GeoHash编码值,非经纬度

与其他方案对比

特性Redis GEO专业GIS粗略计算
精度
功能基础完善有限
性能
成本
适用简单场景专业应用粗略估算

要点总结

  • GEO基于ZSet实现,经纬度编码为GeoHash作为score
  • GEOADD添加地理位置,GEOPOS获取坐标
  • GEODIST计算两点距离,支持m/km/mi/ft单位
  • GEOSEARCH查询附近地点,Redis 6.2+推荐使用
  • GeoHash前缀相似表示地理位置相近
  • 应用场景:附近人、附近门店、打车配送、地理围栏
  • 有效经度范围:-180到180,纬度:约-85到85
  • 距离计算误差约0.5%,实际可接受
  • 单个GEO集合建议不超过10万数据
  • 底层是ZSet,可使用ZSet命令批量操作
  • 简单地理场景用Redis GEO,专业GIS用专业方案

📝 发现内容有误?点击此处直接编辑

← 上一篇 HyperLogLog
下一篇 →
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库