Redis GEO 地理位置搜索:实战示例 + 底层原理解析
📝 文章概要
Redis 不仅是高性能的键值数据库,还内置了地理位置(GEO)功能,支持存储经纬度并快速查询附近的地点。本篇文章将通过示例讲解如何在 Redis 5.x 中使用 GEO 命令进行地理位置存储与范围搜索,并解析其底层实现原理,让你不仅会用,还能理解背后的机制。
📝 文章内容
1️⃣ Redis GEO 简介
Redis GEO 命令允许我们:
存储带经纬度的地理位置
查询某个点附近的对象(半径范围)
计算两点距离
获取位置坐标
GEO 命令适用于 Redis 5.x:
GEOADD、GEORADIUS、GEORADIUSBYMEMBER、GEODIST、GEOPOS、GEOHASH。
2️⃣ GEO 命令示例
2.1 添加城市地理位置
# 创建 key 为 city_geo 的地理数据集合
GEOADD city_geo 116.403963 39.915119 "北京·天安门"
GEOADD city_geo 121.473701 31.230416 "上海·外滩"
GEOADD city_geo 113.264385 23.129112 "广州·天河"
GEOADD city_geo 114.057868 22.543099 "深圳·福田"
GEOADD city_geo 104.066541 30.572269 "成都·天府广场"
GEOADD city_geo 117.200983 39.084158 "天津·鼓楼"
GEOADD city_geo 118.796877 32.060255 "南京·新街口"
GEOADD city_geo 120.155070 30.274084 "杭州·西湖"
GEOADD city_geo 106.551556 29.563009 "重庆·解放碑"
GEOADD city_geo 87.616848 43.825592 "乌鲁木齐·市政府"
GEOADD city_geo 108.940174 34.341568 "西安·钟楼"
GEOADD city_geo 126.534967 45.803775 "哈尔滨·中央大街"
GEOADD city_geo 91.132212 29.660361 "拉萨·布达拉宫"
GEOADD city_geo 114.305393 30.593099 "武汉·江汉路"
GEOADD city_geo 113.625368 34.746599 "郑州·二七塔"
2.2 查询某城市周边范围
# 按成员查找
GEORADIUSBYMEMBER city_geo "上海·外滩" 500 km WITHDIST WITHCOORD ASC# 按坐标查找
GEORADIUS city_geo 114.057868 22.543099 300 km WITHDIST WITHCOORD ASC
2.3 计算城市间距离
GEODIST city_geo "北京·天安门" "上海·外滩" km
2.4 获取城市经纬度
GEOPOS city_geo "广州·天河"
3️⃣ GEO 存储原理解析
3.1 底层是有序集合 ZSET
GEOADD实际上就是把地理坐标转换为 52 位整数 geohash,然后存入 ZSET 的 score。通过 ZSET 的有序特性,Redis 可以快速查找范围内的元素。
3.2 为什么看不到经纬度?
在 ZSET 内,成员名称保留原名
score 是压缩后的 geohash 编码
使用
GEOPOS可以反解出原始经纬度
3.3 搜索流程
将查询中心点经纬度编码为 geohash
计算半径对应的 geohash 区块
ZSET 范围扫描,获取可能的候选点
精确计算球面距离,过滤出最终结果
4️⃣ 示例:Java Jedis 使用 GEO
Jedis jedis = new Jedis("localhost", 6379);
jedis.geoadd("city_geo", 116.403963, 39.915119, "北京·天安门");
jedis.geoadd("city_geo", 121.473701, 31.230416, "上海·外滩");List<GeoRadiusResponse> results = jedis.georadiusByMember("city_geo","北京·天安门",1500,GeoUnit.KM,GeoRadiusParam.geoRadiusParam().withCoord().withDist().sortAscending()
);for (GeoRadiusResponse r : results) {System.out.println(r.getMemberByString() + " 距离: " + r.getDistance() + "km");
}
5️⃣ 总结
Redis GEO 命令在 Redis 5.x 版本中依赖 ZSET 存储
数据虽然存入 ZSET,但可以通过命令获取精确经纬度
非常适合附近搜索、位置服务等场景
理解底层原理,有助于做性能优化与大数据量处理
