在现代互联网应用中,“附近的人”、“附近的商家”、“打车找司机”等基于地理位置的功能已经非常普遍。你有没有好奇这些功能是如何高效实现的?今天,我们就来深入探讨 Redis 中一个强大又实用的功能——GEO(地理空间索引)。
一、什么是 Redis GEO?
Redis 自 3.2 版本起原生支持 GEO(Geospatial)数据类型。它允许我们将地理位置(经度 longitude 和纬度 latitude)存储为一个有序集合(Sorted Set),并提供专门用于距离计算和范围查询的命令。
底层原理是 GeoHash 算法:将二维经纬度编码为一维字符串(实际以 double 类型作为 score 存入 Sorted Set),从而利用有序集合的结构实现高效的范围检索。
简单来说:
Redis GEO = 经纬度存储 + 高效距离计算 + 圆形/矩形区域搜索
二、核心命令(Redis 6.2+ 推荐用法)
以下是当前(截至 Redis 7.x / 8.x)官方推荐且长期维护的 GEO 命令:
| 命令 | 作用 |
|---|---|
GEOADD key longitude latitude member [longitude latitude member ...] |
添加一个或多个地理位置 |
GEOPOS key member [member ...] |
获取成员的经纬度 |
GEODIST key member1 member2 [unit] |
计算两个成员之间的距离 |
GEOHASH key member [member ...] |
获取成员的 GeoHash 编码(调试用) |
| `GEOSEARCH key FROMMEMBER member BYRADIUS radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC | DESC]` |
GEOSEARCH key FROMLONLAT longitude latitude BYRADIUS radius unit [...] |
以指定经纬度为中心,搜索圆形区域(替代 GEORADIUS) |
GEOSEARCH key FROMLONLAT longitude latitude BYBOX width height unit [...] |
搜索矩形区域内的位置(新增能力!) |
✅ 单位支持:
m(米)、km(千米)、ft(英尺)、mi(英里)
✅GEOSEARCH支持 圆形(BYRADIUS) 和 矩形(BYBOX) 两种搜索方式,功能更强大
三、实战:用 GEOSEARCH 实现“附近的人”
假设我们开发一个社交 App,用户上线时上报位置,其他用户可查看“5 公里内”的在线好友。
步骤 1:添加用户位置
用户上线时,将 ID 和经纬度存入 GEO key:
GEOADD nearby_users 116.48 39.95 user:1001
GEOADD nearby_users 116.50 39.96 user:1002
GEOADD nearby_users 116.30 39.90 user:1003 # 较远
支持批量添加,性能更优。
步骤 2:查找附近的人(以经纬度为中心)
用户 A(位置 116.48, 39.95)想查 5 公里内的人:
GEOSEARCH nearby_users
FROMLONLAT 116.48 39.95
BYRADIUS 5 km
WITHDIST
WITHCOORD
COUNT 20
ASC
返回示例(格式化后):
1) 1) "user:1001"
2) "0.0000" // 距离(km)
3) 1) "116.480003356933594" // 经度
2) "39.950000772859696" // 纬度
2) 1) "user:1002"
2) "2.3121"
3) 1) "116.500003337860107"
2) "39.9600007635355"
ASC表示按距离由近到远排序(默认),DESC则相反。
步骤 3:以已有成员为中心搜索(更简洁)
如果用户已存在于 GEO 集合中,可直接以其 ID 为圆心:
GEOSEARCH nearby_users
FROMMEMBER user:1001
BYRADIUS 5 km
WITHDIST
COUNT 10
无需重复传经纬度,代码更清晰,也避免坐标误差。
步骤 4:进阶:矩形区域搜索(外卖/地图场景)
比如用户拖动地图,划定一个矩形区域(西南角 116.40,39.90,东北角 116.50,39.98):
GEOSEARCH nearby_users
FROMLONLAT 116.45 39.94
BYBOX 10 8 km
WITHCOORD
注意:
BYBOX width height unit表示以中心点为基准,向东西延伸width/2,南北延伸height/2。
若需任意矩形,建议在应用层用圆形多次查询,或结合其他 GIS 系统。
四、关键注意事项与最佳实践
1. 坚决弃用 GEORADIUS
GEORADIUS和GEORADIUSBYMEMBER在 Redis 6.2+ 已标记为 deprecated。- 虽然目前仍能运行,但未来版本可能移除,新项目禁止使用。
- 所有新代码请统一使用
GEOSEARCH。
2. 数据更新与过期
- 用户下线时,应主动删除其位置:
ZREM nearby_users user:1001 - 可结合 Redis 的键过期机制(如为每个用户设独立 GEO key 并设 TTL),或通过定时任务清理“心跳超时”的用户。
3. 性能表现
GEOSEARCH时间复杂度为 **O(log(N) + M)**,N 为总元素数,M 为返回结果数。- 百万级数据下,毫秒级响应完全可行。
4. 精度限制
- Redis GEO 精度约 0.5~1 米,适用于 LBS 场景,但不适用于高精度测绘或导航。
5. 不支持复杂地理操作
- 无法计算路径、多边形包含、行政区划等。
- 如需高级 GIS 功能,建议搭配 PostGIS、Elasticsearch(geo_point)等专业工具。
五、适用场景总结
✅ 非常适合:
- 社交:“附近的人”
- O2O:“附近门店/骑手/司机”
- 游戏:“周围玩家/NPC”
- IoT:“附近设备定位”
❌ 不适合:
- 高精度地图服务
- 路径规划(如导航)
- 复杂地理围栏(如不规则多边形)
六、结语
Redis GEO 是一个轻量、高效、易用的地理空间解决方案。随着 GEOSEARCH 的引入,其功能更完整、接口更统一,已成为构建实时位置服务的首选工具之一。
记住:从 Redis 6.2 开始,请用 GEOSEARCH,告别 GEORADIUS!
现在,只需几行命令,你就能为你的应用加上“附近的人”功能——快去试试吧!

评论 (0)