全国村级GeoJSON数据下载:70万村庄的量级、乡镇归属校验与切片避坑
数据的另一半:全国村级GeoJSON数据下载的量级、归属校验与切片坑
给区县做完边界清洗之后,我最常收到的一类提问是:"你省市区县都有,村级要不要也来一套?能不能全国村级 GeoJSON 数据下载?"
说实话村级是另一套玩法。省一年变不了几次,市偶尔撤并改,区县一年动个几十个算大年,但村(含社区居委会)全国近 70 万个(民政部口径含社区约 66–70 万,村约 47–50 万),属性字段更薄、编号更碎片化、来源更杂。这篇写我实际跑村级数据时踩的四个坑,帮想接手的少走弯路。
一、先认清村级数据到底"少"在哪
县级以上的 GeoJSON 结构基本稳定:省-市-区县 三级前缀、民政部代码基本能对齐、属性表至少有 name 和 code。村级一进来就乱了:
- 编号体系断档。村级没有独立的 12 位统计用码与 12 位民政码双轨,很多时候只能拿到民政部乡镇级之下的村级"顺序号",也就是区划代码后补两位,例如
510722(三台县)+ 乡镇码 + 村序后凑成不规整的一串。能不能拼、拼错了归属哪里,要先核对乡镇归属。 - 城乡属性全靠猜。村级常只有 name/code 两列,居委会(111/shape 属性常常为空),"村委会 vs 社区"要靠编号后 3 位或聚类来判定,误差在所难免。
- 多边形质量差异大。村级很多源是"行政村界由自然村合并近似"而来,缝隙、重叠、飞地比县级以上常见得多。
所以做全国村级 GeoJSON 数据下载,第一件事不是急着下载,而是定"基准乡镇集合",把每个村的父级对到某个确切乡镇代码上,否则后续钻取、统计全都会错位。
二、把村级挂回乡镇:一套可复用的归属校验流程
承接系列 51 的"数据先行"思路,村级最该做的是"父级对齐 + 面积甄别"。我用的流程大致是这样(伪码,仅示意思路,避免把可执行路径写死):
// 1. 读乡镇级基准 polygon 集合 T(平铺后的 code -> geometry)
// 2. 读村级要素 C,找每个 C 的候选父乡镇:点在内 / 面重叠占比最大
for (const feat of villages) {
const pt = intersectPointOf(feat) // 村级面质心
const parent = tIndex.pointIn(pt) // 质心落在哪个乡镇面
feat.parentCode = parent?.code ?? null // 匹配不到 => 记缺
if (!parent) orphans.push(feat) // 常见于飞地村 / 合并残留
}
// 3. 面积甄别:村级 union(geometry) 超出父乡镇 1.5x => 标记存疑
跑完会得到三张表:正常归属、孤儿村(质心悬空)、面积异常村。孤儿的通常不是真缺,而是村级边界与乡镇基准之间存在历史合并后的旧版残留,或者被相邻乡镇吞并但旧数据没删。这是最容易误判的一类,先人工看地图再决定去留,别一删了事——和区县那批"特殊区独立飞地"同理。
三、文件体积与切片:村级没法整县一个 GeoJSON 硬塞
区县面一个文件常见几百 KB 到几 MB,浏览器扛得住。村级不一样——一个地级市可能就有几千个村,整市导出一个未化简 GeoJSON 随随便便十几 MB,前端 fetch 加 JSON.parse 加上 Leaflet/MapLibre 逐要素添加,秒级会卡。
我当时的处理是分层 + 服务端预切片:
| 目的 | 做法 | 预期收益 |
|---|---|---|
| 列表加载 | 只传 name/code 的轻量索引 JSON,不传 geometry | 首屏几十 KB |
| 详情渲染 | 单村或一镇范围再拉要素 GeoJSON | 单请求可控 |
| 全图预览 | 用 Turf 的 simplify 预生成 1:100 万以下低精度版 | 骨架拖拽流畅 |
| 生产导出 | 源数据另存未化简版走付费按次/按日下载 | 保精度的归导出 |
另外一个潜移默化的坑是 winding order 和单位。村级数据来自不同处理管线,有的经纬度是度,有的被转成米制的投影坐标却没写 crs,拼进同一图层会直接错位到海里去。接之前先抽样看前几个坐标的数值量级,比跑完全量再返工便宜得多。
四、缓存与交付:村级页也得套上下钻那套刷新纪律
村级页面一旦做进同体系(/省/市/区县/村 下一级钻取),缓存刷新就得复用顶层那条红线:任何刷新只做 files 级 / Type:file 单条 URL,绝不整站或按主机名全站刷,否则会误伤同前缀下其它还没变化的 JSON。geo 数据与页面走 ESI(边缘拼接)或静态烘焙,务必保证"代码变少、页面全改"时才动全量重生成;日常维护只重生成真正变化的那几级,改完做源站哈希审计,确认上传的只有 changed 文件。
五、小结:村级能下载,但要先约法三章
如果你想直接用,建议按这三条验证:
1. 村级必须带父级乡镇 code,不能只有村名,否则全国拼不到一起; 2. 拿县级面积做一遍 union 重叠甄别,圈出孤儿与存疑再决定取舍; 3. 大批量拉取走轻量索引 + 单要素详情 + 付费导出分层,别指望一次十 MB 全塞浏览器。
我的体会是:村级的价值不在"多边形有多精确",而在能不能和各上级无缝钻下去 + 属性字段够不够支撑统计。属性对齐做到位,村级的面精度做二次抽稀后做展示完全够用;真要数调用,还是那句——本站数据预览免费,导出一份全量边界才 ¥1.99/次,按需拿,别囤。
想找村级数据的,可以直接在全国省市区县 geojson 数据下载那套体系里按"乡镇列表 → 村级子集"去拆;而全国省市区县区划边界数据下载那几级的校验逻辑,也完全能下沉到村级这一层复用,原则和上面一致。GeoJSON 格式处理、坐标系转换这些基本功,前面系列已经写过不少,这篇就当给村级补齐临门一脚。