核心是坐标顺序(经度在前、纬度在后)和单位大小写(必须小写如"km"),错则导致查不到人、距离错误或返回空;go客户端需显式传坐标,不支持直接用member名查询。

Go 用 Redis 做 GEO 半径搜索,核心就两点:坐标顺序不能错,单位大小写必须对。 其他问题基本都是这两点衍生出来的——比如查不到人、距离算错、返回空数组,八成是 GEOADD 把纬度当经度传了,或者 GEORADIUS 里写了 KM 而不是 km。
Go 客户端调用 GeoRadius 必须显式传经纬度
Redis 的 GEORADIUS 命令不认 member 名,只认坐标。Go 客户端(如 github.com/redis/go-redis/v9)没有自动帮你查 GeoPos 再转发的逻辑,你得自己把用户当前坐标(比如从 App 上报来的)作为参数传进去。
- 错误写法:
client.GeoRadius(ctx, "users:geo", "u123", &redis.GeoRadiusQuery{...})→ Go 客户端不支持这种语法,会编译失败 - 正确写法:
client.GeoRadius(ctx, "users:geo", lng, lat, &redis.GeoRadiusQuery{Radius: 1000, Unit: "m", WithDist: true, WithCoord: true, Count: 20}) -
Unit字段必须是小写:"m"、"km"、"mi"、"ft";写成"KM"直接报ERR unknown unit - 如果要按距离升序排,加
Sort: "ASC";默认不排序,结果顺序不可靠
GEOADD 参数顺序是经度在前、纬度在后
这是最常踩的坑。MySQL 的 POINT(lat, lng)、高德/百度 SDK 返回的 [lat, lng] 数组习惯,会让人下意识反着传。但 Redis GEO 硬性要求:longitude 第一,latitude 第二。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 错误示例:
&redis.GeoLocation{Latitude: 31.205593, Longitude: 121.446617, Name: "u123"}→ 字段名没错,但如果你从手机 SDK 拿到的是[lat, lng]数组,直接塞进Latitude/Longitude字段,就等于把纬度当经度用了 - 更隐蔽的错法:调用
GeoAdd时手动传参顺序错,比如client.GeoAdd(ctx, key, lat, lng, "u123")→ 实际存的是南美洲某点 - 批量添加安全些:一次塞多个
*redis.GeoLocation,避免单条命令反复往返,也减少手误概率 - 注意坐标系:Redis 默认用 WGS84,国内安卓部分厂商 GPS 返回的是 GCJ-02 偏移坐标,不转换就存,搜索圈会整体偏移几百米
查不到附近用户?先盯住这三个地方
代码能跑通、没报错,但 GeoRadius 返回空 slice,大概率不是逻辑问题,而是数据层偏差被低估了。
-
key不一致:存的时候用"users:geo",查的时候写了"user_geo"或"geo:users",Redis 当作两个不同集合处理 - 半径设太小:设了
Radius: 100单位"m",但用户间球面距离是 105.3 米 → Redis 按 Haversine 算出来就是超了,不命中 - 没加调试参数:默认只返回
member名字,看不出是不是真在范围内。上线前务必带WithDist: true和WithCoord: true,拿到距离和坐标才能验证是否合理 - 极点附近失效:纬度超出
-85.05112878到85.05112878范围,GeoAdd不报错但存不进,后续所有查询都为空
性能与兼容性:老版本 Redis 只能用 GEORADIUS
GEOSEARCH 是 Redis 6.2+ 才有的命令,语义更清晰(支持 FROMMEMBER),但如果你线上 Redis 还是 6.0 或更早,就得坚持用 GEORADIUS + GeoPos 两步走。
- 两步写法:先
client.GeoPos(ctx, key, "u123").Result()拿坐标,再拼GeoRadius查询 —— 多一次 round-trip,延迟增加约 0.5~2ms(局域网) - 数据量大时,
Count不能代替分页:比如Count: 20是取最近 20 个,但无法跳过前 20 取第 21~40 个;真要分页得结合Store+ZRANGEBYSCORE自己实现 - 20 万条数据下,搜 50km 范围平均 6ms,搜 200km 可能到 30ms+;如果 P99 延迟卡在 10ms 内,建议把半径控制在 5km 以内,或预热常用区域缓存
真正难的不是写对那几行 Go 代码,而是确认手机上报的坐标到底是 WGS84 还是 GCJ-02,以及接受 Redis Geohash 本身有 ±0.5% 的距离误差——它不是数学精确解,而是一个为速度妥协的空间索引方案。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










