文章目录

Redis Geo地理位置功能实现附近商家搜索

发布于 2026-04-20 13:18:39 · 浏览 2 次 · 评论 0 条

Redis Geo地理位置功能实现附近商家搜索

Redis 的 Geo 模块基于有序集合(ZSET)实现,底层将经纬度通过 Geohash 算法转换为 52 位的字符串索引。这种机制使得在处理地理位置计算时,依然保持 ZSET 的高效读写性能。以下将分步骤演示如何从零开始构建一个“附近商家”搜索功能。


核心原理简述

Geo 类型本质上是经纬度与成员名称(如商家 ID)的映射。在底层存储时,Redis 将二维的经纬度映射为一维的 52 位整数,作为 ZSET 的 Score。这样,计算“附近”的任务就转化为计算分数范围内的任务,利用 ZSET 的跳跃表实现快速查询。


步骤一:录入商家位置数据

首先需要将商家的经纬度信息存储到 Redis 中。使用 GEOADD 命令可以一次性添加一个或多个地理位置。

  1. 打开终端或命令行工具。
  2. 连接到 Redis 服务。
  3. 输入以下命令向名为 shops 的键中添加三个商家:星巴克、麦当劳和肯德基。
GEOADD shops 116.404269 39.915168 starbucks
GEOADD shops 116.407826 39.914936 mcdonalds
GEOADD shops 116.401394 39.913942 kfc

参数说明:

  • shops:集合的键名。
  • 116.404269:经度。
  • 39.915168:纬度。
  • starbucks:商家标识(member)。
  1. 确认数据已添加。可以通过 ZCARD shops 查看元素数量。

步骤二:计算两地之间的距离

在用户查看某个商家详情时,通常需要计算该商家与用户当前位置的直线距离。使用 GEODIST 命令即可完成。

  1. 输入以下命令计算“星巴克”与“肯德基”之间的距离,单位指定为千米。
GEODIST shops starbucks kfc km
  1. 查看返回结果。如果输出 0.4189,表示两者相距约 0.42 公里。

支持的单位包括:m(米)、km(千米)、mi(英里)、ft(英尺)。


步骤三:查询附近的商家(核心功能)

这是实现“附近搜索”的关键步骤。假设用户当前位于经度 116.405528,纬度 39.915678(天安门附近),需要查找方圆 500 米内的所有商家,并按距离由近及远排序。

  1. 输入以下命令执行范围查询。
GEORADIUS shops 116.405528 39.915678 500 m WITHDIST WITHCOORD ASC

参数解释:

  • 116.405528 39.915678:中心点经纬度。
  • 500 m:半径 500 米。
  • WITHDIST同时返回距离中心点的直线距离。
  • WITHCOORD同时返回商家的经纬度。
  • ASC距离从近到远排序。
  1. 观察返回结果。结果通常以数组形式展示,包含商家名称、距离和坐标。

步骤四:优化查询结果

在实际业务中,不需要一次性返回所有几百个附近的商家,通常只需要最近的 5 个或 10 个。可以通过 COUNT 参数限制返回数量,提高传输效率。

  1. 输入以下命令,仅查找距离最近的 2 家商家。
GEORADIUS shops 116.405528 39.915678 500 m WITHDIST COUNT 2 ASC
  1. 对比步骤三的结果,此时列表只会包含距离最近的两个元素。

步骤五:业务逻辑流程图

为了更直观地理解数据流向,以下展示了用户发起请求到获取商家列表的完整处理流程。

graph LR A["用户端: 发送 GPS 坐标"] --> B["API 网关"] B --> C["应用服务器: 编写 Redis 命令"] C --> D["Redis: 执行 GEORADIUS"] D --> E["数据库: 返回排序后的商家列表"] E --> C C --> F["应用服务器: 组装 JSON 数据"] F --> G["用户端: 渲染附近商家列表"]

步骤六:Python 代码实战

以下是一个使用 Python 的 redis-py 库封装的完整示例,模拟了一个简单的 API 逻辑。

  1. 安装 Redis 客户端库。
pip install redis
  1. 创建名为 geo_demo.py 的文件,并写入以下代码。
import redis

# 1. 连接到 Redis
r = redis.Redis(host='localhost', port=6379, db=0)

def add_shops():
    # 2. 批量添加商家数据
    # 格式: mapping = {member: (longitude, latitude)}
    shop_locations = {
        "starbucks": (116.404269, 39.915168),
        "mcdonalds": (116.407826, 39.914936),
        "kfc": (116.401394, 39.913942),
        "subway": (116.408528, 39.918678)
    }
    r.geoadd("shops", shop_locations)
    print("商家数据已添加。")

def find_nearby_shops(longitude, latitude, radius=1000):
    # 3. 查找附近商家
    # unit='m' 表示单位为米
    # withdist=True 返回距离
    # sort='ASC' 按距离升序排列
    results = r.georadius(
        name="shops", 
        longitude=longitude, 
        latitude=latitude, 
        radius=radius, 
        unit='m', 
        withdist=True, 
        withcoord=True, 
        sort='ASC',
        count=5  # 限制返回5个
    )

    print(f"当前位置 ({longitude}, {latitude}) 附近 {radius}米 内的商家:")
    print("-" * 50)

    # 格式化输出结果
    for result in results:
        name = result[0].decode('utf-8')
        distance = round(result[1], 2)
        lon = round(result[2][0], 6)
        lat = round(result[2][1], 6)
        print(f"商家: {name}")
        print(f"距离: {distance} 米")
        print(f"坐标: [{lon}, {lat}]")
        print("-" * 50)

if __name__ == "__main__":
    # 初始化数据
    add_shops()

    # 模拟用户位置(例如:天安门东地铁站附近)
    user_lon, user_lat = 116.407526, 39.904030

    # 执行搜索
    find_nearby_shops(user_lon, user_lat, radius=2000)
  1. 运行脚本。
python geo_demo.py
  1. 查看控制台输出的商家列表,程序会自动列出距离指定坐标最近的 5 家商家及其精确距离。

常用命令速查表

下表汇总了开发过程中最常用的命令及其作用。

命令名称 作用 常用参数示例
GEOADD 添加地理位置坐标 GEOADD key lng lat member
GEODIST 计算两个成员间距离 GEODIST key member1 member2 unit
GEOHASH 获取成员的 Geohash 字符串 GEOHASH key member
GEOPOS 获取成员的坐标 GEOPOS key member
GEORADIUS 以坐标为中心查询附近 GEORADIUS key lng lat radius unit
GEORADIUSBYMEMBER 以成员为中心查询附近 GEORADIUSBYMEMBER key member radius unit

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文