我们即将开启一个非常有意思且极其贴近日常生活的模块——附近商铺。
无论是美团的“附近的美食”、微信的“附近的人”,还是滴滴的“附近车辆”,底层都离不开对地理位置(经纬度)的存储与范围计算。在传统关系型数据库(如 MySQL)中计算两点之间的球面距离极其耗费性能,而 Redis 提供了一个堪称完美的数据结构:GEO。
📚 实战篇 11. 附近商铺 - Redis GEO 核心学习文档
一、 核心认知:什么是 Redis GEO?
GEO 就是 Geolocation(地理位置)的简写。它是 Redis 在 3.2 版本 中引入的一个专门用来处理地理空间信息的数据结构。
它允许你将特定的坐标(经度、纬度)与一个具体的元素(比如商铺 ID、用户 ID)绑定存储在 Redis 中,并提供了非常丰富的距离计算和范围检索功能。
🌟 面试高频考点:GEO 的底层到底是什么?
面试官:“Redis 有 5 大基础数据类型,GEO 属于哪一种?”
你的回答: “GEO 并不是一种全新的底层数据结构,它的底层其实就是 SortedSet (ZSet) 。Redis 利用了一种叫做 GeoHash 的算法,将二维的经纬度坐标(Longitude, Latitude)转换成了一个一维的整数值,并将这个整数值作为 ZSet 的
score(分数),将具体的商铺 ID 作为value存入其中。因此,几乎所有 ZSet 的命令(如ZREM,ZRANGE)都可以直接用于 GEO 数据。”
二、 核心命令实操指南
要玩转 GEO,你需要掌握以下几个核心命令。我们以存储商铺(shop)的位置为例:
1. 添加地理位置:GEOADD
-
语法:
GEOADD key longitude latitude member [longitude latitude member ...] -
作用: 将一个或多个经纬度坐标及对应的商铺 ID 添加到特定的 Key 中。
-
演示: ```bash
向北京的商铺集合中,添加天安门(商铺1)和长城(商铺2)的位置
GEOADD shops:beijing 116.397128 39.916527 "shop_1" 116.011934 40.358904 "shop_2"
*(注意:坐标必须是**先经度,后纬度**。有效的经度从 -180 度到 180 度,有效的纬度从 -85.05112878 度到 85.05112878 度。)*
2. 获取地理位置:GEOPOS
- 语法:
GEOPOS key member [member ...] - 作用: 根据商铺 ID,查出它对应的经纬度。
- 演示:
GEOPOS shops:beijing "shop_1"
3. 计算两点间距离:GEODIST
-
语法:
GEODIST key member1 member2 [m|km|ft|mi] -
作用: 计算同一个 Key 中,两个已知元素之间的直线距离(球面距离)。
-
演示: ```bash
计算天安门到长城的距离,单位为千米(km)
GEODIST shops:beijing "shop_1" "shop_2" km
4. 搜索附近范围 (核心大招):GEOSEARCH 🌟
注意:在老版本的 Redis 中,通常使用 GEORADIUS 或 GEORADIUSBYMEMBER。但在 Redis 6.2 版本之后,官方强烈建议废弃它们,统一使用功能更强大的 GEOSEARCH。
-
语法:
GEOSEARCH key FROMMEMBER member | FROMLONLAT longitude latitude BYRADIUS radius m|km|ft|mi [ASC|DESC] [COUNT count] [WITHCOORD] [WITHDIST] -
作用: 根据指定的中心点(可以是一个已知的商铺,也可以是直接传一个经纬度),查找指定半径范围内的其他元素。
-
演示场景: 我现在站在天安门广场(经度 116.397, 纬度 39.916),想看看方圆 5 公里内(距离由近到远排列)最多 10 家商铺,并显示具体距离:
Bash
GEOSEARCH shops:beijing FROMLONLAT 116.397 39.916 BYRADIUS 5 km WITHDIST ASC COUNT 10(参数解析:
WITHDIST代表返回结果时带上距离,ASC代表由近到远排序,COUNT 10代表只取前 10 个)
三、 业务场景与架构思考
在真实的黑马点评项目中,“附近商铺”功能的典型业务流程如下:
- 缓存预热(数据同步): 系统启动或定时任务触发时,从 MySQL 数据库中把所有商铺的经纬度数据读取出来,利用
GEOADD批量写入 Redis。通常会按照城市或者商圈对 Key 进行分类存储(例如shop:geo:beijing),防止单个 Key 数据量过大(大 Key 问题)。 - 前端传参: 用户在 App 端授权获取地理位置后,前端将用户的实时经度(
longitude)和纬度(latitude)传给后端接口。 - Redis 范围检索: 后端拿着用户的坐标,利用
GEOSEARCH FROMLONLAT ...命令,从 Redis 中极速查出附近 5 公里内的商铺 ID 和距离。 - 数据拼装: 后端拿着查出来的商铺 ID,去 MySQL(或另外的 Redis 缓存)中查出商铺的具体信息(图片、名称、评分),将距离字段拼接进去,最终返回给前端渲染。
学习总结
Redis GEO 是解决空间范围搜索的最佳轻量级方案。它巧妙地利用了数学上的 GeoHash 降维算法,把复杂的二维球面坐标距离计算,转化为了对 ZSet 结构的高效检索,极大地释放了关系型数据库的计算压力。
**