GEOADD 必须经度在前、纬度在后,错位会导致位置偏移;GEOSEARCH 功能更全且支持 FROMMEMBER,GEORADIUS 需显式传坐标;查不到附近用户主因是坐标系偏差、半径过小或 key 不一致。

怎么用 GEOADD 往 Redis 写入位置数据
必须严格按「经度在前、纬度在后」的顺序传参,Golang 客户端(比如 github.com/go-redis/redis/v8)不会校验坐标合法性,错位会导致所有查询结果偏移甚至为空。
- 错误写法:
geoAdd("users:geo", lat, lng, "u123")→ 实际存的是“纬度当经度、经度当纬度”,地图上会飞到南美洲内陆 - 正确写法:
geoAdd("users:geo", lng, lat, "u123"),例如上海某点:121.446617(经度)、31.205593(纬度) - 批量添加更安全:一次
GEOADD命令塞多个点,避免网络往返和事务开销;Redis 底层用zset存,member 重复时自动覆盖旧坐标
GEORADIUS 和 GEOSEARCH 该选哪个
GEOSEARCH 是 Redis 6.2+ 引入的新命令,功能更全、语义更清晰,但老项目若还在用 6.0 或更早版本,只能靠 GEORADIUS。
-
GEORADIUS要求显式传入经纬度,适合「已知用户当前坐标」的场景,比如 App 端上报定位后查附近人:GEORADIUS users:geo 121.446617 31.205593 1 km WITHDIST -
GEOSEARCH支持以 member 名为圆心(如GEOSEARCH users:geo FROMMEMBER u123 BYRADIUS 1 km),省去先查GEOPOS再调用半径搜索的两步,也支持矩形范围(BYBOX),适合服务端聚合逻辑 - 注意单位参数:
m(米)、km、mi、ft必须小写,写成KM会报错ERR unknown unit
为什么查不到预期的 nearby 用户
常见不是代码写错,而是坐标精度或误差被低估了 —— Redis 的 GeoHash 编码本身有约 ±0.5% 的距离误差,且极点附近不可用。
- 用户坐标来自手机 GPS,但未做 WGS84 坐标系校验:国内安卓部分厂商 SDK 返回 GCJ-02 偏移坐标,直接扔进 Redis 会导致搜索圈偏移数百米
- 半径设太小:比如设
100 m,但两个用户实际直线距离 105 米,Redis 按球面大圆距离算出来就是 105.3 米,不命中 - key 没统一:用户位置存在
users:geo,但店铺存在shops:geo,却用同一个 key 去查,自然为空 - 没加
WITHDIST或WITHCOORD参数:默认只返回 member 名,看不出是不是真在范围内,调试时务必带上
Go 客户端实操要注意的坑
用 go-redis 时,GEOADD 的参数顺序和返回值类型容易混淆,尤其和 SQL 风格 ORM 养成的习惯冲突。
立即学习“go语言免费学习笔记(深入)”;
-
client.GeoAdd(ctx, "users:geo", &redis.GeoLocation{Longitude: lng, Latitude: lat, Name: "u123"})—— 注意字段名是Longitude/Latitude,不是Lng/Lat -
GEORADIUS返回的是[]*redis.GeoLocation,但Dist字段单位是「你传的 unit 对应的数值」,比如单位填"km",Dist就是千米,不是米 - 别用
client.Do(ctx, "GEORADIUS", ...)手拼命令:类型不安全,参数顺序一错就静默失败;优先用封装好的方法 - 高并发写位置时,建议加 pipeline 批量提交,单个
GEOADD在万级 QPS 下可能成为瓶颈
真正麻烦的从来不是调通命令,而是坐标的来源是否可信、单位是否一致、误差是否在业务容忍范围内。比如「附近 500 米」对共享单车是刚需,对找餐厅可能 1 公里都行 —— 别让技术方案替产品做取舍。


















