实战篇 11. 附近商铺 - Redis GEO 核心学习文档

3 阅读4分钟

我们即将开启一个非常有意思且极其贴近日常生活的模块——附近商铺

无论是美团的“附近的美食”、微信的“附近的人”,还是滴滴的“附近车辆”,底层都离不开对地理位置(经纬度)的存储与范围计算。在传统关系型数据库(如 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 中,通常使用 GEORADIUSGEORADIUSBYMEMBER。但在 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 个)


三、 业务场景与架构思考

在真实的黑马点评项目中,“附近商铺”功能的典型业务流程如下:

  1. 缓存预热(数据同步): 系统启动或定时任务触发时,从 MySQL 数据库中把所有商铺的经纬度数据读取出来,利用 GEOADD 批量写入 Redis。通常会按照城市或者商圈对 Key 进行分类存储(例如 shop:geo:beijing),防止单个 Key 数据量过大(大 Key 问题)。
  2. 前端传参: 用户在 App 端授权获取地理位置后,前端将用户的实时经度(longitude)和纬度(latitude)传给后端接口。
  3. Redis 范围检索: 后端拿着用户的坐标,利用 GEOSEARCH FROMLONLAT ... 命令,从 Redis 中极速查出附近 5 公里内的商铺 ID 和距离。
  4. 数据拼装: 后端拿着查出来的商铺 ID,去 MySQL(或另外的 Redis 缓存)中查出商铺的具体信息(图片、名称、评分),将距离字段拼接进去,最终返回给前端渲染。

学习总结

Redis GEO 是解决空间范围搜索的最佳轻量级方案。它巧妙地利用了数学上的 GeoHash 降维算法,把复杂的二维球面坐标距离计算,转化为了对 ZSet 结构的高效检索,极大地释放了关系型数据库的计算压力。


**