GeoHash与GeoJSON详解

📅2026/7/11 20:49:32 👁️次浏览
GeoHash与GeoJSON详解
GeoHash与GeoJSON详解做附近的人、外卖配送范围、地图标注或空间检索时常会碰到GeoHash和GeoJSON——前者把经纬度压成短字符串做索引后者用 JSON 精确描述点线面。二者不是替代关系GeoHash 偏「附近搜索与粗索引」GeoJSON 偏「几何表达与地图展示」。速览GeoHash经纬度 → 一维字符串Z 阶曲线二分前缀相同 ≈ 位置相近适合 Redis/DB 索引。GeoJSONRFC 7946 矢量格式数据交换用空间查询靠 PostGIS / R-tree / GeoHash 等索引。坐标顺序GeoJSON 为[经度, 纬度]lng, lat与部分 API 习惯相反集成时易错。国内地图对外常用 WGS84高德/腾讯为GCJ-02百度为BD-09不做转换会偏几百米。核心结论30 秒版附近搜索 / LBS 索引→ GeoHash简单或 S2 / H3大规模、更均匀。地图展示 / 前后端交换几何→GeoJSON。数据库空间查询→ WKT/WKB PostGIS 等对外接口仍可包一层 GeoJSON。热力图 / 六边形聚合→H3。国内接地图 SDK 必做坐标系转换。目录1. 二者定位2. GeoHash3. GeoJSON4. 对比与分工5. 类似编码与格式6. 坐标系与投影7. 场景选型速查8. 工程实践要点8.4 典型事故边界只查一格8.5 最小可行示例附近 1km 店铺9. 延伸阅读1. 二者定位典型用途表达与索引原始位置经度 纬度点 / 线 / 面几何GeoHash 字符串GeoJSON Feature附近搜索 / Redis 索引地图渲染 / API 交换概念本质一句话GeoHash编码算法把二维坐标压成一维字符串便于前缀检索「附近」GeoJSON数据格式JSON精确描述地理要素的几何与属性2. GeoHashGeoHash将经度、纬度编码为Base32 字符串如wx4g0基于对经纬度区间反复二分按 Z 阶曲线Morton code交织成一维序列。2.1 核心特点项说明输入经度 纬度通常 WGS84输出字母数字短串长度可变性质二维 → 一维近似位置非精确坐标存储检索前缀匹配≈ 同一矩形区域适合 B-tree、RedisZRANGEBYLEX等2.2 精度与长度参考字符越长格子越小赤道附近大致量级纬度越高单格越窄长度约略宽度 × 高度5~4.9km × 4.9km6~1.2km × 0.6km7~153m × 153m8~38m × 19m9~4.8m × 4.8m上表为赤道附近量级纬度越高经向东西越窄。例如在北京约 40°N长度为6时格子约东西 0.6km × 南北 1.2km——不是正方形前缀检索时要有体感。示例天安门附近(116.397128, 39.916527) → wx4g0长度依实现与截断而定2.3 典型场景场景用法附近的人 / 店 / 车存 GeoHash查当前格 相邻 8 格边界问题Redis / DB 索引按前缀或范围扫描LBS 粗筛外卖、打车、共享单车第一轮过滤2.4 局限集成必知问题说明边界效应相距很近的两点可能落在相邻格子前缀完全不同 → 需查8 邻居或降精度非均匀高纬度格子经向更窄球面曲率下非严格「正方形」不适合展示不能画多边形样式需解码或另存 GeoJSON一维排序前缀相近 ≠ 欧氏距离最近多数场景够用用户位置 P计算 GeoHash g当前格 8 邻居前缀/范围查询 Redis 或 DB业务过滤精确距离、营业状态等2.5 Redis Geo 与手写 GeoHashRedis 提供GEOADD/GEORADIUS/GEODIST等命令底层同样基于GeoHash 有序集合但封装了编码、邻居与距离计算开箱即用。方式适用Redis Geo 命令POI 量级中等、固定「附近 N km」、不想维护 8 邻居逻辑手写 GeoHash ZRANGEBYLEX需自定义精度、多级回退、与其他字符串索引混排PostGIS / S2 / H3千万级 POI、复杂围栏、要与 SQL 空间算子统一Redis Geo 屏蔽了 8 邻居细节但边界漏检问题依然存在实现已处理邻居若业务要按 GeoHash 前缀做分片、冷热分层或跨存储引擎对齐仍建议理解并手写 GeoHash 逻辑。3. GeoJSONGeoJSONRFC 7946用 JSON 表示地理要素几何geometry 可选属性properties。3.1 几何类型类型含义Point点LineString折线Polygon面外环 可选内环/洞MultiPoint / MultiLineString / MultiPolygon同类要素集合GeometryCollection异构几何集合3.2 要素封装类型说明Feature单个要素geometrypropertiesFeatureCollection多个 Feature 的数组3.3 示例带属性的点{type:Feature,geometry:{type:Point,coordinates:[116.397128,39.916527]},properties:{name:天安门}}坐标顺序coordinates为[longitude, latitude]经度在前。与部分「先纬后经」接口混用时画反到海上是常见 bug。3.4 Polygon 注意RFC 7946 要求外环逆时针、内环洞顺时针右手规则。首尾坐标闭合首尾为同一点。Leaflet、Mapbox GL等主流 SDK 展示时往往会自动修正环方向写入PostGIS或做ST_Contains等空间计算前建议用库校验/修复如ST_MakeValid。复杂面用于配送范围、围栏、行政区。3.5 GeoJSON 不是空间索引GeoJSON 是数据交换格式描述「有什么几何、什么属性」不包含R-tree、网格索引或查询能力。大规模「范围内有哪些要素」仍需数据库PostGIS GiST 索引、ST_DWithin缓存/中间层GeoHash / S2 / H3粗筛应用内R-tree如 JTS STRtree常见组合PostGIS 存 WKB 索引算查询 → API 层序列化为 GeoJSON 返回。3.6 典型场景场景说明Web 地图Leaflet、Mapbox GL、OpenLayers 原生支持前后端 API统一交换点线面GIS 管线导入导出中间格式常与 PostGIS 互转空间分析叠加、缓冲、包含关系多在 GIS 引擎内4. 对比与分工对比项GeoHashGeoJSON本质编码算法数据格式几何隐含矩形格显式点线面精度近似取决于长度精确双精度浮点存储短字符串索引友好JSON体积较大展示不适合适合附近搜索强项前缀需 R-tree / PostGIS 等索引格式本身不索引典型组合粗筛 GeoHash → 精算 HaversineAPI 返回 GeoJSON Feature需求推荐「把坐标变成字符串快速找附近」GeoHash「用 JSON 精确描述地图图形」GeoJSON5. 类似编码与格式5.1 空间索引 / 网格编码类 GeoHash方案特点典型场景GeoHash实现简单、前缀检索Redis 附近、中小规模 LBSS2 GeometryGoogle球面 Cell、64 位 CellID高纬更均匀Google Maps、Foursquare 级海量索引H3Uber六边形网格、多分辨率网约车热力、配送分区、聚合统计MGRS军事网格字母数字测绘、野外、军事对比GeoHashS2H3实现复杂度低高中格子形状矩形曲线边界四边形六边形邻居均匀性一般好好六邻5.2 矢量数据格式类 GeoJSON格式说明WKT文本POINT(116.397 39.916)PostGIS、ST_GeomFromTextWKBWKT 二进制紧凑存储与传输KML / KMZXMLGoogle Earth偏标注与可视化Shapefile经典 GIS 多文件政府/规划Web 侧常转 GeoJSON5.3 一张总表类型代表空间索引GeoHash / S2 / H3 / MGRS矢量格式GeoJSON / WKT / WKB / KML / Shapefile坐标系WGS84 / GCJ-02 / BD-09 / UTM6. 坐标系与投影6.1 常用地理坐标系国内必看名称说明常见使用方WGS84EPSG:4326GPS 原始经纬度GeoJSON 默认、国际地图、raw GPSGCJ-02国测局偏移俗称「火星坐标」高德、腾讯、国内多数图商BD-09在 GCJ-02 上再次加密百度地图GPS 设备 (WGS84) ──转换──► GCJ-02高德/腾讯 SDK └──► BD-09百度 SDK未转换直接打点偏移可达数百米。入库建议统一基准常存 WGS84展示层按图商 SDK 转换。6.2 UTM 与投影UTM横轴墨卡托将经纬度投影为米制平面坐标分带使用多用于测量、工程、军事与 Web 常用经纬度 GeoJSON 并存。7. 场景选型速查你想做的事推荐主力备注Web 地图展示GeoJSON注意[lng, lat]附近搜索 / RedisGeoHash或Redis GEO记得 8 邻居自定义精度可手写海量分布式空间索引S2实现成本高热力图 / 六边形聚合H3Uber 开源库全语言DB 空间查询WKT/WKB PostGIS对外可包 GeoJSON政府 GIS 数据接入Shapefile → GeoJSONogr2ogr / QGISGoogle Earth 标注KML/KMZ非通用 API 格式国内接高德/百度GCJ-02 / BD-09 转换与 WGS84 分层存储技术栈常见组合Java 后端JTS / Spatial4j Redis GeoHash 或 PostGISPythongeohash2/h3/shapely GeoJSONNodengeohash/h3-jsturf.jsGommcloughlin/geohash/uber/h3-go8. 工程实践要点8.1 GeoHash 查询套路对用户坐标算 GeoHash选定长度 业务精度。查询当前格 8 个相邻格内的候选集。用Haversine或数据库球面距离做精确排序与截断。热点区域可降一位精度扩大召回再精筛。规模边界千万级 POI 下单纯「GeoHash 8 邻居 全量 Haversine」CPU 压力会明显上升可考虑降精度扩大候选集 限流二次筛选一级索引改用S2 / H3或PostGISST_DWithin热点商圈结果缓存用户格 营业时段维度8.2 GeoJSON 接口约定统一CRS对外声明 WGS84国内图商层再转。字段命名type/geometry/properties/features保持规范避免私有嵌套破坏兼容性。大面数据考虑简化几何Douglas-Peucker或按 zoom 分级下发控制 payload。8.3 常见误区误区事实GeoHash 等于精确坐标近似格中心高精度需存原始 lat/lngGeoJSON 先纬后经标准为经度在前存 GeoHash 就不用 GeoJSON展示、围栏、路线仍需矢量格式国内地图直接用 GPS 坐标必须过 GCJ-02 / BD-09只查当前 GeoHash 格边界点会漏检 →8 邻居GeoJSON 自带空间查询能力只是 JSON 格式索引与算子在 DB / 中间件8.4 典型事故边界只查一格某次「附近门店」上线后上海用户反馈列表里混入大量苏州/杭州门店且直线距离明明 500m 的店反而搜不到。排查发现实现只对用户当前 GeoHash单格做前缀查询未合并8 邻居边界上的用户与门店落在相邻格召回为空或错位。修复后召回正常再用 Haversine 截断 1km。教训GeoHash 检索默认按「当前格 8 邻居」设计单格查询是常见线上事故源。8.5 最小可行示例附近 1km 店铺请求示意GET /api/shops/nearby?lng116.397lat39.916radius_m1000服务端逻辑Python 伪代码importgeohash2frommathimportradians,sin,cos,sqrt,atan2 PRECISION6# ~1km 量级按业务调defneighbors9(lat,lng):ggeohash2.encode(lat,lng,precisionPRECISION)return{g}|set(geohash2.neighbors(g).values())# 当前格 8 邻居defhaversine_m(lat1,lng1,lat2,lng2):R6371000p1,p2radians(lat1),radians(lat2)dp,dlradians(lat2-lat1),radians(lng2-lng1)asin(dp/2)**2cos(p1)*cos(p2)*sin(dl/2)**2return2*R*atan2(sqrt(a),sqrt(1-a))defnearby_shops(user_lng,user_lat,radius_m):cellsneighbors9(user_lat,user_lng)candidatesshop_repo.find_by_geohash_prefixes(cells)# Redis ZRANGEBYLEX 或 DBreturn[sforsincandidatesifhaversine_m(user_lat,user_lng,s.lat,s.lng)radius_m]响应GeoJSONFeatureCollection坐标 WGS84[lng, lat]{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[116.401,39.918]},properties:{id:shop_12,name:示例咖啡,distance_m:420}}]}索引层用GeoHash粗筛对外用GeoJSON表达结果几何——即二者最常见的分工。9. 延伸阅读资源说明RFC 7946 GeoJSON格式规范geojson.org说明与示例S2 GeometryGoogle 球面索引Uber H3六边形网格PostGIS 文档WKT/WKB 与空间 SQLOGC Simple FeaturesWKT/WKB 标准来源落地时确认业务精度 ↔ GeoHash 长度、坐标系入库基准、地图 SDK 展示层转换策略空间索引只是第一层过滤最终距离与围栏仍以几何计算为准。收束GeoHash 解决「怎么快速找附近」GeoJSON 解决「怎么准确描述与交换图形」大规模索引可看 S2/H3数据库内算 WKT/PostGIS国内链路永远把坐标系单独当成一层。验证环境WGS84EPSG:4326GeoJSON RFC 7946Python 3.11geohash2 / h3-py 4.x、Node 18ngeohash、PostGIS 3.3、Redis 7.x GEO 命令