Redis GEO 介绍与实战:轻松实现“附近的人”功能

在现代互联网应用中,“附近的人”、“附近的商家”、“打车找司机”等基于地理位置的功能已经非常普遍。你有没有好奇这些功能是如何高效实现的?今天,我们就来深入探讨 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

  • GEORADIUSGEORADIUSBYMEMBER 在 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)

暂无评论