GEOSEARCH 更适合打车场景,因其支持 BYRADIUS + SORTBY + WITHCOORD 一次性完成查询、排序与坐标返回,避免 GEORADIUS 需额外调用 GEODIST 导致的延迟,且不依赖过时的 key 存在性判断。

为什么 GEOSEARCH 比 GEORADIUS 更适合打车场景
因为司机位置是动态高频更新的,而乘客发单后需要「实时、低延迟」拿到附近可用司机——GEOSEARCH 支持用 BYRADIUS + SORTBY + WITHCOORD 一次性完成查询+排序+坐标返回,且不依赖过时的「key 是否存在」判断逻辑。GEORADIUS 在 Redis 6.2+ 虽然也能做类似事,但默认不返回距离字段,要额外调 GEODIST,多一次 round-trip,打车这种毫秒级敏感场景会明显拖慢首屏匹配速度。
常见错误现象:GEORADIUS 返回空结果,但司机明明在范围内——其实是没设 WITHDIST 或用了旧版 Redis(
-
GEOSEARCH必须搭配STOREDIST或WITHDIST才能知道每个司机离乘客多远,否则只给坐标,你没法筛“3 公里内” - 如果司机数超 1000,建议加
MAXLEN 1000防止网络传输和客户端解析卡顿 -
SORTBY只支持升序(ASC),想按距离由近到远排必须写SORTBY dist ASC,写DESC会报错
司机位置怎么存才不会查不准
司机上线/移动时,必须用 GEOADD 实时更新,但关键点在于:key 名不能是固定字符串(比如 drivers),而要带业务维度隔离,否则高峰期多个城市共用一个 key 会导致 GEO 索引冲突或误匹配。
使用场景:北京司机和深圳司机绝不能混在一个集合里查,否则乘客在北京发单,可能捞出 500km 外的深圳司机。
- 推荐 key 格式:
drivers:beijing、drivers:shenzhen,城市编码从订单里取,别硬编码 - 司机
member用唯一 ID(如driver:12345),别用昵称或手机号——后者含特殊字符可能触发 GEOADD 解析失败 - 经纬度必须用 double 类型传入,
"116.397"字符串会报错ERR invalid longitude, latitude
乘客下单时怎么用 GEOSEARCH 拿到最近 20 个司机
不是直接搜半径,而是先用乘客坐标为中心,搜一个略大的圆(比如 5km),再按真实距离过滤到 3km 内,并取前 20 个——这样既保证召回率,又避免漏掉刚好卡在 3km 边缘的司机。
GEOSEARCH drivers:beijing FROMMEMBER passenger:789 BYRADIUS 5 km WITHCOORD WITHDIST SORTBY dist ASC MAXLEN 20
注意:这里 passenger:789 是乘客的 member 名,也得提前用 GEOADD 加进同一个 key(或用临时 key 存一次),否则 FROMMEMBER 找不到坐标会返回空。
- 如果乘客没预存坐标,得改用
FROMLOCALE,格式是FROMLOCALE 39.916 116.397,注意顺序是lat lng,反了就偏到蒙古国 -
MAXLEN 20是截断数量,不是“最多返回 20 个在范围内的”,它是在整个 5km 圆里按距离排完再截,所以要配合SORTBY dist ASC - 返回结果里
dist单位是请求时指定的(km/m),别拿m的值去跟3km比较
为什么线上总出现“匹配不到司机”,但日志显示 GEOSEARCH 有返回
大概率是客户端或下游服务没正确处理 GEOSEARCH 的响应结构。Redis 返回的是扁平数组,不是 JSON 对象:每组结果占 4 个元素(member, distance, longitude, latitude),没字段名,靠位置索引取值。
容易踩的坑:
- 把返回当字典解析,比如用
result["dist"]—— 实际是result[1],下标越界就取错数据 - 没检查
distance是否为"0"(字符串)或nil(某些驱动会转成 null),导致“距离 0 米”的司机被当成异常丢弃 - 前端或调度模块把
longitude和latitude顺序颠倒传给地图 SDK,图标全飘到南美洲
最常被忽略的一点:GEOSEARCH 不保证结果一定在请求半径内——它只保证中心点到集合成员的球面距离 ≤ 半径,但如果你用 FROMLOCALE 输错了 lat/lng,或者司机坐标本身精度差(比如用高德 GCJ-02 坐标直接当 WGS-84 存),算出来的“3km 内”可能是假的。










