Skip to content

采集运维手册

年度校准、增量采集与数据质量维护的操作规程。

采集运维手册(Runbook)

面向维护者。定义 post-stats.gov.cn 时代的采集节律、增量/全量两条管线的操作步骤、产物合并策略与层级冻结边界。 依据:数据采集现状评估与提升路径采集能力提升实施计划

1. 采集节律(对齐法定发布机制)

《行政区划代码管理办法》(民政部令第79号,2025-09-01 施行)第十六条确立:国务院民政部门每年 1 月通过国家地名信息库(dmfw)发布截至上年末的全国各级行政区划代码。据此,采集分两条节律:

节律触发管线目的
年度全量校准每年 1 月(法定发布后)dmfw 全量 BFS → 差分基线 → patch与官方年度发布对齐,重建当年全量基线
日常增量变更事件驱动(周/月轮询)xzqh 变更公告 → NLP 抽取 → patch捕捉年内新设/撤并/更名,无需全量重爬

首年确认:79 号令 2025-09 才生效,2026-01 是首个完整履行周期。执行年度校准前,先人工确认 dmfw 数据现势日期(抽查任一节点,确认已更新至上年 12-31),再触发全量,避免抓到未更新的旧态。

2. 日常增量:xzqh 事件驱动(首选)

xzqh 是权威变更事件源,带明确批复机关+日期,仍优于"dmfw 全量差分反推变更"(后者为推断、无批复证据)。

注:dmfw 差分曾会混入 dmfw/NBS 层级口径差异造成的伪变更(48 直辖市区 + 5 省直管市假 move),该问题已由 diffToPatch 内置的 canonicalizeParent 归一化关闭(见 §3 与 memory crawler-dmfw-nbs-level-mismatch);xzqh 首选是因证据等级更高,而非 dmfw 层级不可用。

bash
# 抓某年《县级以上行政区划变更情况》→ NLP 抽取 → 产出 draft patch
pnpm --filter @cndiv/crawler crawl:xzqh --year=2026
# 或用已构建的 bin
cndiv-xzqh --year=2026
  • 数据源:xzqh.mca.gov.cn/description?dcpid=<年份>dcpid 即 4 位年份,GBK 编码,无 RSS/API)。
  • 覆盖:县级以上变更(设立/撤销/更名/驻地迁移/隶属调整)。1999–2026 连续;2022 年无发布(县级调整冻结期)属正常。
  • 产物:合法 operationsvalidatePatch 守门;新设实体无既有码 → 落 unresolved 待人工分配码后补 add不臆造码)。
  • 监控建议:周级轮询 xzqh 当年页面,内容差分发现新条目即触发抽取。

3. 年度全量校准:dmfw BFS 差分

bash
# 全国全量(每年 1 月,对齐 2023 基线)
pnpm --filter @cndiv/crawler crawl --year=2026 --baseline=packages/source-2023/data/divisions.csv
# 分省验证/分批:--root=640000000000
# 断点续爬:相同 --cache 目录重跑即续跑
  • 引擎:getList JSON 接口 + maxLevel=2 步长 BFS(全国全量 ~461 请求,见 T1.1)。
  • 覆盖:level 1–4(省/市/县/乡镇街道),无村级
  • 层级归一化(自动)diffToPatch 内置 canonicalizeParent——以 12 位码结构派生父码覆盖 dmfw 上报的扁平父码,对基线/当前两侧施加;isPlaceholder 在 remove 分支豁免「市辖区 / 省直辖县级行政区划」占位层。故直辖市区/省直管市的层级建模差异不再产假 move/假 remove,无需人工预对齐(首跑 92 假 ops 已归零)。
  • 差分默认抑制 remove--removes=off):dmfw 覆盖 < NBS,"基线有、dmfw 无"多为口径差异而非真实撤销;需人工复核时 --removes=on
  • 产物按省切分写 patches/<year>/<省码>0000000000-dmfw-<year>.json,逐个经 validatePatch 守门。

4. 两条管线的产物合并与去重

两条管线都产出 patches/<year>/*.json,应用顺序与去重原则:

  1. 事件流优先:xzqh 抽取的变更带明确批复机关+日期(权威证据),置信度高于 dmfw 全量差分的推断。
  2. 同码冲突:同一 code 若 xzqh 与 dmfw 都有操作,以 xzqh(事件源)为准;dmfw 差分结果作交叉印证。
  3. 应用即校验(两道守门)cndiv apply-patch 前所有 patch 必过 ① validatePatch(字段形状,pnpm validate-patches)+ ② cndiv-verify --mode=structural(码/层级/父级自洽 + 对 baseline 引用完整性,schema 之上的语义层)。两者 CI 已接入,任一 error 阻断。详见 patch-校验与交叉校验
  4. 置信度分级official_nbs > mca_decree > community > shadow_map(见 spike 文档)。

4.2 结构性门禁 cndiv-verify(本地/CI 通用)

bash
# 提 patch 前本地自查(CI 同款门禁):任一 error → 退出码 1
cndiv-verify --mode=structural --patch=patches --baseline=packages/source-2023/data/divisions.csv
  • 离线确定性:只读 baseline 码集 + 码工具,无网络——门禁不会因 dmfw 反爬随机变红。
  • 门禁红了怎么办:看规则 id 定位。ADD_PARENT_MISMATCH/ADD_LEVEL_MISMATCH=码与声明不自洽(多为手写 patch 笔误或未归一化的外部 patch);TARGET_MISSING/ADD_DUPLICATE=引用了 baseline 不存在/已存在的码(常是虚构码或基线年份错配);*_MISSING 为 warning 不阻断(多跨 patch 引用)。
  • 商业地图交叉校验--mode=cross合规桩,商业源三重禁止(存储/构建数据集/分发),仅限本地手动、只读、产物不落库,不接入 CI、不入 MIT 再分发

4.1 合并工具 cndiv merge-patches(T2.3)

多份 patch 先合并去重成单一成品,再交 apply-patch(apply-patch 单文件事务不变):

bash
cndiv merge-patches --dir=raw/2026 --out=patches/2026/2026.merged.json
# 可选覆盖优先级:--priority=xzqh,community,dmfw(高→低)
  • 管线优先级xzqh > community > dmfwcommunity 居中是本手册的运维判断——社区提交经人工核证、证据等级通常介于事件流与全量差分之间;如某年社区质量存疑,用 --priority 临时降级。
  • 冲突键 = code:同一 code 被多管线触碰时,败者该 code 上所有 op 整组落 sidecar<out>.conflicts.json)。注意:若败者带正交操作(如 dmfw 同 code 的 move 与 xzqh 的 rename 无关),也会连带进 sidecar——冲突报告须人工过一遍,字段级合并暂不做(Occam)。
  • 管线判定:优先读 patch meta.source_pipeline(生产者 cndiv-crawldmfwcndiv-xzqhxzqh,单一真相源);仅当缺该字段(老/手写 patch)时才回退文件名/author 启发式(含 xzqh→xzqh,含 dmfw→dmfw,否则 community)。故新产 patch 无需依赖文件名辨识,社区手写 patch 建议显式写 meta.source_pipeline 以免启发式误判。
  • 其它不变量:完全相同 op 去重、add vs remove 同 code 保留 add、输出恒序 add→move→update→removeapply_after 不一致直接报错拒合并。

5. 层级冻结边界(T2.2)

level 5 村级(村委会/居委会,NBS 2023 基线 620,572 条)已永久冻结

  • 官方无活源:79 号令法定代码体系只到乡级(九位码:街道/镇/乡/民族乡/区公所);村/居委会是基层群众性自治组织,非行政区划建制。dmfw 接口结构性止于 level 4,高德等商业源亦止于街道。完整论证见 spike-village-level5
  • 冻结地板:NBS 2023 村级作为不可增量的冻结地板(source_type=official_nbs);村级变更(撤并/新设社区/更名)走既有 Patch 通道(patches/),来源为各地民政局公示的 NLP 抽取,而非全量爬虫。
  • 差分不变量diffToPatch 默认 levels=[1,2,3,4],对 level5 不产出任何 add/update/remove(由 test/diff.test.ts 固化)。仅当显式传 levels=[5] 时才比对——排除是默认策略而非硬编码禁止。

数据侧说明:packages/source-*/data/*.csv.gitignore 不入库(走 NPM/Release 分发),故冻结状态以本文档 + spike 文档 + 测试断言声明,不逐行改数据。

6. 工程注意(反爬/稳定性)

  • dmfw/xzqh 均为政府接口,无 SLA、路径会漂移(已实锤 /server/resource.html/resource.html)。采集失败逐 code 记录、可续爬;接口契约建议纳入定期 smoke test(见 plan T3.2)。
  • dmfw getList 有间歇性抖动(同 root 连查偶有丢子树);全量校准后应比对总条数量级(全国 ~2446 条 level1-4 或按当年)确认无系统性丢失,failures 节点重跑补齐。
  • 数据不进 git.cache/、大 SQLite/CSV 走 .gitignore 内容型规则 + pre-commit 钩子(见 memory data-asset-backup)。

7. 年度校准提醒

.github/workflows/annual-recalibration-reminder.yml 于每年 1 月中旬自动开 issue 提醒执行年度全量校准。注意:GitHub 对 60 天无提交活动的仓库会自动禁用 scheduled workflow,长期休眠后需手动重新启用或 workflow_dispatch 触发。

数据来源于公开政府网站(国家统计局、民政部国家地名信息库),仅供学习与研究使用。代码以 MIT 许可。