Redis能做GIS查询吗?Geo命令怎么用?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

引言

很多做 WebGIS、位置服务或移动端地图项目的同学都会问:Redis能做GIS查询吗?Geo命令怎么用? 简短答案是:Redis 可以做一部分轻量级 GIS 查询,尤其适合“附近的人”“附近门店”“按半径查点位”这类高并发、低延迟的空间检索场景。

但 Redis Geo 不是 PostGIS,也不是完整的 GIS 空间数据库。它主要处理经纬度点位的存储、距离计算和范围查询,不适合复杂面叠加、缓冲区分析、拓扑关系判断、投影转换等传统 GIS 分析任务。本文从 GIS 使用者的角度,讲清楚 Redis Geo 命令能做什么、怎么用、什么时候该用、什么时候不该用。

Redis Geo GIS查询与Geo命令半径查询流程示意图
Redis Geo 适合把经纬度点位写入内存索引,并快速返回指定半径内的附近目标。

背景

在 GIS 项目中,常见的空间查询可以分为两类:

  • 业务型位置查询:例如查找附近 3 公里内的门店、车辆、设备、人员。
  • 分析型空间查询:例如点面叠加、道路缓冲区、行政区裁剪、栅格统计、空间连接。

Redis Geo 更偏向第一类,也就是业务系统中的实时位置查询。它的优势是速度快、部署轻、接口简单,适合放在 WebGIS 服务端作为位置检索缓存或实时位置索引。

如果你的需求是“用户打开地图后,快速显示附近 50 个停车场”,Redis Geo 很合适。如果你的需求是“判断建筑物是否落在某个规划红线面内”,Redis Geo 就不合适,应该使用 PostGIS、ArcGIS Pro、QGIS 或 GeoPandas 等工具。

原理

Redis Geo 的核心思想是:把经纬度点编码成可排序的空间编码,并存储在 Redis 的有序集合结构中。用户查询附近点时,Redis 先根据空间编码筛选候选对象,再计算距离并返回结果。

在使用 Redis Geo 做 GIS 查询前,需要明确三个关键点:

  • 只支持点数据:Redis Geo 存储的是 longitude、latitude 和 member,不能直接存 Polygon、LineString 等复杂几何。
  • 使用 WGS84 经纬度:经度范围通常为 -180 到 180,纬度范围通常为 -85.05112878 到 85.05112878。
  • 适合球面距离近似:Redis 的距离计算适合常见位置服务,但不应替代严肃测绘或投影坐标下的精确面积、长度分析。

从 GIS 角度理解,Redis Geo 更像一个“高性能点位附近查询索引”,而不是完整的空间数据库。它能回答“离我近的点有哪些”,但不能完整回答“这个面与哪些地块相交”。

步骤

1. 准备测试数据

假设我们要做一个“附近门店查询”功能,点位数据包含门店 ID、经度、纬度和名称。示例数据如下:

门店ID 名称 经度 纬度
shop:1001 人民广场店 121.4751 31.2304
shop:1002 南京东路店 121.4846 31.2381
shop:1003 陆家嘴店 121.4998 31.2397

2. 使用 GEOADD 写入点位

Redis Geo 使用 GEOADD 命令写入经纬度点。注意参数顺序是经度、纬度、成员名,不要写反。

GEOADD shops:shanghai 121.4751 31.2304 shop:1001
GEOADD shops:shanghai 121.4846 31.2381 shop:1002
GEOADD shops:shanghai 121.4998 31.2397 shop:1003

也可以一次写入多个点:

GEOADD shops:shanghai 
  121.4751 31.2304 shop:1001 
  121.4846 31.2381 shop:1002 
  121.4998 31.2397 shop:1003

这里的 shops:shanghai 可以理解为一个点位图层或空间索引集合,里面保存了上海门店的点位。

3. 查询两个点之间的距离

如果要计算两个门店之间的距离,可以使用 GEODIST

GEODIST shops:shanghai shop:1001 shop:1002 km

最后的单位可以使用 mkmmift。在 GIS 项目中,国内业务系统一般使用 mkm

4. 查询指定半径内的点

在较新的 Redis 版本中,推荐使用 GEOSEARCH 做附近查询。例如,以经纬度 121.4800, 31.2350 为中心,查询 2 公里内的门店:

GEOSEARCH shops:shanghai 
  FROMLONLAT 121.4800 31.2350 
  BYRADIUS 2 km 
  WITHDIST 
  ASC

这个命令的含义是:

  • FROMLONLAT:从指定经纬度作为查询中心。
  • BYRADIUS 2 km:查询半径为 2 公里。
  • WITHDIST:返回每个点到中心点的距离。
  • ASC:按距离从近到远排序。

这就是 Redis Geo 最典型的 GIS 查询用法:输入一个当前位置,返回附近点位,并按距离排序。

5. 限制返回数量

实际 WebGIS 接口通常不希望一次返回太多点位。可以使用 COUNT 限制数量:

GEOSEARCH shops:shanghai 
  FROMLONLAT 121.4800 31.2350 
  BYRADIUS 5 km 
  WITHDIST 
  ASC 
  COUNT 20

这个查询适合“附近 20 个门店”“附近 10 辆车”“最近 50 个传感器”等业务场景。

6. 查询矩形范围内的点

除了半径查询,GEOSEARCH 也支持矩形范围查询,例如查询中心点附近宽 5 公里、高 3 公里的范围:

GEOSEARCH shops:shanghai 
  FROMLONLAT 121.4800 31.2350 
  BYBOX 5 3 km 
  WITHDIST

需要注意,矩形范围不是地图视口的严格投影矩形,而是 Redis Geo 支持的一种近似空间范围检索方式。如果你需要严格按 Web Mercator 地图视口裁剪,建议在服务端结合 PostGIS 或在 Redis 返回候选点后再做二次过滤。

7. 在 Python 中调用 Redis Geo

如果你使用 Python 开发 WebGIS 后端,可以通过 redis-py 调用 Redis Geo。示例代码如下:

import redis

r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

# 写入点位
r.geoadd(
    "shops:shanghai",
    [
        121.4751, 31.2304, "shop:1001",
        121.4846, 31.2381, "shop:1002",
        121.4998, 31.2397, "shop:1003",
    ],
)

# 查询附近门店
result = r.geosearch(
    "shops:shanghai",
    longitude=121.4800,
    latitude=31.2350,
    radius=2,
    unit="km",
    withdist=True,
    sort="ASC",
    count=20,
)

for item in result:
    print(item)

不同版本的 Python Redis 客户端在参数形式上可能略有差异。实际项目中建议先用 Redis 命令行验证 GEOADDGEOSEARCH 正常,再封装到后端接口中。

常见坑

1. 经纬度顺序写反

这是 Redis Geo GIS 查询中最常见的问题。GEOADD 的顺序是:

GEOADD key longitude latitude member

也就是先经度,再纬度。如果把纬度写在前面,点位会被放到错误位置,附近查询结果就会非常异常。

2. 坐标系不一致

Redis Geo 使用经纬度坐标,通常应使用 WGS84。很多国内地图业务会遇到 GCJ-02、BD-09、WGS84 混用的问题。如果前端地图、后端数据库和 Redis Geo 使用的坐标系不一致,点位会出现偏移。

建议在入库前统一坐标系,并在字段或文档中明确标注。例如:

  • Redis Geo 索引统一使用 WGS84。
  • 前端高德地图展示时再转换为 GCJ-02。
  • PostGIS 原始数据保留 SRID 信息,避免数据来源混乱。

3. 把 Redis 当成完整 GIS 数据库

Redis Geo 不能直接执行 ST_IntersectsST_WithinST_Buffer 这类空间分析函数。它不适合管理复杂几何、行政区边界、规划红线、地块面数据。

如果你的查询逻辑需要点面关系判断,应该优先考虑 PostGIS;如果需要桌面端处理,可以使用 QGIS 或 ArcGIS Pro。

4. 半径设置过大导致结果过多

Redis 很快,但如果半径过大、点位密度很高、返回数量不限制,仍然可能导致接口响应变慢、网络传输变大、前端地图渲染卡顿。

建议:

  • 设置合理半径,例如 1 公里、3 公里、5 公里。
  • 使用 COUNT 限制返回数量。
  • 必要时按城市、业务区域或网格拆分 key。

5. 忽略数据更新策略

如果是车辆、人员、设备等实时位置,点位会频繁变化。此时需要考虑更新频率、过期策略和离线清理。

常见做法是:

  • GEOADD 更新同一个 member 的最新位置。
  • 用普通 key 保存对象状态和时间戳。
  • 定期清理长时间未上报的对象。

方法比较

Redis Geo、PostGIS 和传统 GIS 工具都能处理空间数据,但适用场景不同。不要只看“能不能查附近”,还要看数据类型、查询复杂度、精度要求和系统架构。

方案 适合场景 优势 限制
Redis Geo 附近门店、附近车辆、实时点位查询 速度快、接口简单、适合高并发 主要支持点位,不适合复杂 GIS 分析
PostGIS 点线面空间查询、空间分析、空间索引 GIS 能力完整,支持复杂几何和空间函数 部署和 SQL 设计要求更高
QGIS / ArcGIS Pro 数据检查、制图、空间分析、人工处理 可视化强,工具丰富 不适合作为高并发在线查询服务
GeoPandas 离线批处理、空间数据清洗、分析脚本 适合 Python 数据处理流程 不适合直接承担在线高并发服务

一个更稳妥的工程架构是:PostGIS 保存权威空间数据,Redis Geo 保存热点点位索引,前端 WebGIS 只请求当前视野或当前位置附近的必要结果。

检查清单

在把 Redis Geo 用到正式 GIS 项目前,可以按下面的清单检查:

  • 是否确认需求只是点位附近查询,而不是复杂空间分析?
  • 是否统一了坐标系,避免 WGS84、GCJ-02、BD-09 混用?
  • GEOADD 是否使用经度在前、纬度在后?
  • 是否为不同城市、租户或业务类型设计了合理的 Redis key?
  • 查询时是否使用 COUNT 限制返回数量?
  • 是否需要按距离排序,并返回 WITHDIST
  • 实时位置数据是否有更新时间戳和离线清理机制?
  • 是否在 PostGIS 或原始数据库中保留权威数据,而不是只依赖 Redis?
  • 是否对前端地图渲染数量做了限制,避免一次加载几千个点?
  • 是否用真实业务点位测试过边界情况,例如跨城市、海量点、坐标异常?

FAQ

Redis 能做 GIS 查询吗?

Redis 能做一部分 GIS 查询,主要是基于经纬度点位的附近查询、距离计算和范围检索。它适合位置服务中的实时点位查询,但不能替代 PostGIS 这类完整空间数据库。

Redis Geo 命令怎么用?

常用命令包括 GEOADDGEODISTGEOSEARCH。一般流程是先用 GEOADD 写入点位,再用 GEOSEARCH 按半径或矩形范围查询附近点,并用 WITHDIST 返回距离。

Redis Geo 可以存面数据吗?

不适合。Redis Geo 主要存经纬度点位,不能像 PostGIS 那样直接存储和分析 Polygon、MultiPolygon、LineString 等复杂几何。如果要做点面叠加或行政区判断,建议使用 PostGIS。

Redis Geo 查询结果为什么位置不对?

最常见原因有两个:一是经纬度顺序写反,二是坐标系不一致。请确认 GEOADD 使用的是 longitude、latitude 顺序,并确认前端地图、后端数据和 Redis Geo 使用同一套坐标标准或有明确转换流程。

Redis Geo 和 PostGIS 怎么选?

如果需求是高并发附近点查询,可以用 Redis Geo。如果需求包括空间关系判断、复杂几何分析、空间索引 SQL 查询和权威空间数据管理,应使用 PostGIS。实际工程中,两者经常配合使用:PostGIS 管权威数据,Redis Geo 做热点位置索引。

Redis Geo 适合 WebGIS 吗?

适合一部分 WebGIS 场景,尤其是地图上显示附近门店、车辆、人员、设备等点位。为了避免前端卡顿,应限制查询半径和返回数量,并只加载当前业务需要的点。

结论

Redis Geo 可以做 GIS 查询,但它解决的是“经纬度点位附近查询”这一类具体问题,而不是完整的 GIS 空间分析。对于附近门店、附近车辆、实时设备定位这类场景,Redis Geo 命令简单、响应快,非常实用。

使用时要重点注意三件事:坐标系统一、经纬度顺序正确、返回数量受控。如果项目还涉及点面关系、复杂几何、空间分析和长期数据管理,建议把 Redis Geo 与 PostGIS、QGIS 或 ArcGIS Pro 搭配使用。这样既能保证在线查询性能,也能保留 GIS 数据处理的完整能力。