GeoJSONcn
GeoJSONcn / 技术专栏 / 省市区县边界 GeoJSON 整…

省市区县边界 GeoJSON 整文件读太慢?转 GeoParquet 列存,按需只取要的那几列

发布于 2026-09-09 · GeoJSONcn 技术团队 · 阅读约 8 分钟

全国省市区县geojson数据下载回来那种几百 MB 的整文件,真正磨人的常常不是画图,而是"想核对一小块也得整份读完"。行式 GeoJSON 按文件整体编排:你要查某个地市辖区边界或属性,脚本也得先 JSON.parse 全部、再遍历每一个 feature 才递到目标。实测一份数百 MB 的全国文件,只为取 geometry 一个字段也得先解完整棵对象树;换列存后,同样的按需读取能只动命中的那几个行组。工程上自然会想到列存——把各属性列与几何列分开压缩,查询时只解压用到的少几列。GeoParquet 就是把这条思路固化进开放标准的做法:GeoJSON 只转一次,往后高频查询的带宽与内存可以省下一个量级。这篇用一份全国区县边界的真实维护场景讲清两边账、一份转换命令和三个坑。

整文件全读 vs 列存按需:差在读多少

归档后最常见的活不外三种:按名字筛出某个地市、按 area/population 做统计、把某一层切小块导出。GeoJSON 每一回都逃不掉全量 load;GeoParquet 是另一本账:footer 元数据只有几 KB,各列的 chunk 按行组分块存放,还带 bloom filter。查询写上 WHERE adcode LIKE '4403%' 这种谓词,引擎能直接跳过不含深圳的那些行组;SELECT name, geometry 时,population 一整列根本不进入解压环节。

操作行式 GeoJSON(全读)GeoParquet(列存+剪枝)
只要 1 个属性列得先解析全部几何只解该列 chunk
按 adcode 前缀筛一块全文件逐 feature 遍历bloom/行组跳过,只扫可疑块
峰值内存(区县级约 200MB 源)常放大到 2~3 倍趋近命中子集本身

一次转换要花几十分钟不假,但这张"索引化底图"一旦落地,以后所有"扫一眼、核一小块"的活就都从整文件级落到近单块级。这套收益在我整理全国省市区县区划边界数据下载后的归档件上体会最深。

用 ogr2ogr 转换,别手搓 WKB

没必要为转格式自己写解析器。GDAL 4.x 的 ogr2ogr 原生读 GeoJSON、写出 Parquet,几何统一进 geometry 列(WKB),坐标系写进规范的 geo 元数据。

ogr2ogr -f Parquet 区县.parquet 全国区县.geojson -nln 区县 \
  -lco COMPRESSION=ZSTD \
  -lco GEOMETRY_ENCODING=WKB \
  --config OGR_PARQUET_GEOMETRY_NAME geometry

二进制转完,查询两个落点都顺:后端用 DuckDB spatial 直接 read_parquet('区县.parquet'),WHERE adcode LIKE '4403%' 停在元数据层就把无关行组挡在门外,SELECT name, geometry 也只按需解密几何那段,省的是把坐标点从压缩解码里拉出来的那份 CPU;纯前端则可用 parquet 的表 footer + Range 请求去静态取命中的行组,因为 parquet 天生支持字节范围随机访问——这不依赖任何后端,静态托管也能跑出"按块取数"的效果。

三处落坑,头两条藏得最深

其一,坐标系不可想当然。规范要求几何以 WKB 存、坐标参考写进元数据;转换时若不显式盯住 SRS,源文件若带别的投影就可能被误当 4326 叠上通用底图就飘。转前先 ogrinfo -so 看一眼,需重投影再补 -t_srs EPSG:4326。

其二,adcode 的"类型门"。这类看似纯数字的字段在 GeoJSON 里多半被写成字符串,以保住前导零与固定位长;若图省事按整数列收纳,bloom 里存的是 440305 却拿原文 '440305' 去比,谓词剪枝当场失效,剪枝形同虚设。转换前先把 adcode 定为 text、面积归 double,并让列类型与查询谓词严格同型,否则省下来的带宽全折在这层错配上,排查起来又极绕人。

其三,压缩不叠两层。文件内部已 ZSTD,落地层再包一层 HTTP Brotli 硬压,边缘缓存白耗且易触发内容协商冲突;列存就把压缩权留给格式自身,传输交回边缘。GeoParquet 是给"查得多、切得细"的用途,偶尔只画个全貌的场合直接读回 GeoJSON 反而少一层维护——是否值得列存化,由你的查询密度说了算。

线上这层我还是主张只输出烘焙好的静态结果:裁剪、抽稀、属性瘦身都收进离线脚本,预览请求永远打预设文件,不做服务器端现算,这样把边缘命中和交付成本都压住。真想拿边界去排版面汇报、还要一省一块单独改色,与其在脚本里自己拼图形对象,不如直接取成型素材——去 geojsoncn 的地图 PPT 模板页 按省、按市下钻挑一张可编辑模板,预览满意再下载,幻灯片里就能改色,转换与渲染的功夫一并省下。

一句话收尾:列存并不取代 GeoJSON,二者各安其位。GeoJSON 仍是交换与直接喂地图库的主流形态,负责把全国村级geojson数据下载后的第一批边界快速交付成人人可画;真正被反复拿来统计、比对、切文件的那些才值得多花一步转 parquet 剪枝。先用行式格式让下载即可用,再对高频那份做列存化,两层并行、按数据使用频率分流,算下来成本远没想象中高,收益却落在每次查询都少扛整份文件上。