面试突击第 3 期 | Redis 如何实现查询附近的人?视频实战版

面试突击第 3 期 | Redis 如何实现查询附近的人?视频实战版
最新回答
白小葭

2026-10-20 16:32:22

Redis 通过 GEO 功能实现查询附近的人,主要利用其内置的地理空间索引能力。以下是具体实现方法和关键细节:

1. 核心方法

Redis 的 GEO 功能基于 ZSet 实现,提供以下关键命令:

  • GEOADD:添加地理位置(经度、纬度、成员名称)。
  • GEOPOS:获取成员的经纬度坐标。
  • GEODIST:计算两个成员间的直线距离(支持米、千米、英里等单位)。
  • GEORADIUS / GEORADIUSBYMEMBER:查询指定坐标或成员附近一定范围内的其他成员。
2. 实现步骤(1) 添加位置数据

使用 GEOADD 将用户位置存入 Redis。例如:

GEOADD person 116.404269 39.913164 xiaomingGEOADD person 116.36 39.922461 xiaohong(2) 查询附近的人

通过 GEORADIUSBYMEMBER 查询某用户附近的其他用户。例如,查询小明(xiaoming)周围 5 公里内的人:

GEORADIUSBYMEMBER person xiaoming 5 km WITHDIST

返回结果示例:

1) 1) "xiaohong" 2) "3.9153" # 距离(千米)3. 底层原理
  • 数据结构:GEO 使用 ZSet 存储位置数据,成员名称作为 ZSet 的 member,经纬度通过 GeoHash 编码转换为分值(score)排序。
  • GeoHash:将二维经纬度编码为一维字符串,相邻区域的编码具有相似前缀,便于范围查询。
  • 查询优化:GEORADIUS 会先通过 GeoHash 筛选大致范围,再计算精确距离。
4. 代码实战(Java 示例)

使用 Jedis 客户端实现:

import redis.clients.jedis.*;public class NearbyPeople { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); // 添加位置数据 jedis.geoadd("person", 116.404269, 39.913164, "xiaoming"); jedis.geoadd("person", 116.36, 39.922461, "xiaohong"); // 查询小明附近 5 公里的人 List<GeoRadiusResponse> nearby = jedis.georadiusByMember( "person", "xiaoming", 5, GeoUnit.KM ); nearby.forEach(res -> System.out.println("附近的人:" + res.getMemberByString()) ); }}5. 注意事项
  • 版本要求:需 Redis 3.2+ 版本。
  • 精度问题:GeoHash 编码存在边缘误差,极端情况下可能漏掉邻近点。
  • 性能:范围查询效率高,但海量数据时需分片或结合其他索引优化。
  • 单位选择:距离单位支持米(m)、千米(km)、英里(mi)等。
6. 扩展应用
  • 附近地点搜索:如餐厅、加油站等。
  • 距离计算:结合 GEODIST 实现动态排序(如“按距离由近到远”)。
  • 结合其他数据:将用户 ID 与 GEO 数据关联,查询后通过 ID 获取详细信息。

通过 Redis GEO,可以高效实现基于地理位置的功能,适合 LBS(位置服务)场景。如需更高精度或复杂查询,可考虑结合专业地理数据库(如 PostGIS)。