Skip to content

下一代基础设施架构设计

v2 数据管线的架构决策、组件关系与设计约束。

下一代中国行政区划数据基础设施架构设计

📐 历史设计稿(仅存档):本文为 v2 规划期的 RFC,其中目录结构、source-history、§4.2 等命名/分节为早期设想,部分已被实现取代。权威的仓库结构与用法以根 README.md 为准。

版本:2.0 (RFC) 状态:草案 日期:2026-01-01 对应报告:《中国行政区划数据架构重构与主权数据治理深度研究报告》


1. 架构总览 (System Context)

本架构旨在解决"后统计局时代"的数据断供与仓库膨胀问题。系统从单一的"爬虫-发布"模式,转型为 "多源情报合成 -> 本地 SQLite 核心 -> NPM 分发网络 -> 客户端流式水合" 的现代数据工程链路。

1.1 核心设计原则

原则说明
Code-Data Decoupling (代码数据解耦)Git 仓库不存数据,NPM 仓库不存代码(指数据包)
Sovereign Data Governance (主权数据治理)不依赖单一官方源,建立基于置信度的多源合成机制
Local-First Engineering (本地优先)利用 SQLite 和流式处理,确保在低配置环境下的构建能力
Compliance by Design (合规设计)严格剔除测绘坐标信息,仅维护行政代码拓扑

2. 工程拓扑结构 (Monorepo Topology)

采用 NPM Workspaces(或 pnpm workspace)管理子包,实现职责分离。

graph TD
    Root[Monorepo Root] --> Core[@cndiv/core]
    Root --> CLI[@cndiv/cli]
    Root --> Crawler[@cndiv/crawler]
    Root --> Protocol[@cndiv/data-protocol]

    subgraph "External Data Lake (NPM Registry)"
        Data2023[@cndiv/source-2023]
        Data2025[@cndiv/source-2025]
    end

    CLI -->|Depends| Core
    CLI -->|Depends| Protocol
    CLI -.->|Hydrates| Data2023
    Crawler -->|Depends| Protocol

2.1 子包定义

包名职责描述关键依赖
@cndiv/core核心逻辑:纯计算层。包含 TS 类型定义、Luhn 校验算法、级联推导逻辑。无副作用,可在 Browser/Node/Edge 运行Zero Dependency
@cndiv/cli编排控制:项目的大脑。负责数据下载(Hydration)、SQLite 数据库维护、CSV 流式导出、补丁应用Bin Alias: cndiv
better-sqlite3, cacache, tar-stream, got
@cndiv/data-protocol协议定义:定义 Patch JSON Schema、数据库 Schema、置信度枚举。被 CLI 和 Crawler 共享zodajv
@cndiv/crawler情报采集 (Dev Only):包含针对民政部 PDF、地图 API 的特定爬虫puppeteer, cheerio, pdf-parse

3. 数据生产与分发流水线 (Data Pipeline)

这是架构中最复杂的部分,涵盖从"暗区"获取数据到用户使用的全过程。

3.1 数据源层 (Ingestion Layer)

面对 2024 年后的数据真空,采用多源策略:

数据源说明
Baseline (基准线)2023 年及以前的 stats.gov.cn 历史数据(已清洗存入 SQLite)
Official Decrees (官方公报)民政部发布的县级以上变更通告(PDF/HTML)。通过 crawler 解析为结构化 Patch
Shadow Data (影子数据)高德/腾讯地图 API 的 District 接口。仅用于发现新增的街道/乡镇名称,不存储坐标
Community Patches (社区补丁)分布式贡献的 JSON 补丁文件

3.2 核心处理层 (Processing Layer - SQLite)

弃用原有的 LevelDB (pageCacheDB),迁移至 SQLite。

  • 存储位置~/.cndiv/cache.db(用户本地)或 CI 环境临时构建

数据库 Schema

sql
CREATE TABLE divisions (
    code TEXT PRIMARY KEY,       -- 12位代码
    name TEXT NOT NULL,          -- 名称
    level INTEGER NOT NULL,      -- 层级 (1-5)
    parent_code TEXT,            -- 父级代码 (索引)
    year INTEGER NOT NULL,       -- 数据年份
    status TEXT DEFAULT 'active', -- active, deprecated
    source_type TEXT,            -- 'official_nbs', 'mca_decree', 'community'
    confidence_score INTEGER,    -- 置信度 (0-100)
    UNIQUE(code, year)
);

CREATE INDEX idx_parent ON divisions(parent_code);
CREATE INDEX idx_year ON divisions(year);

3.3 分发层 (Distribution Layer - NPM as Data Lake)

数据不直接进 Git,而是发布为特殊的 NPM 包。

项目说明
包名规范@cndiv/source-<YEAR>(如 @cndiv/source-2025
包内容data.db.gz(压缩的 SQLite 片段)或 data.csv.gz
manifest.json(包含 SHA-512 校验和)
注意package.json 中无 main 字段,防止被误 require
发布策略CI 检测到 SQLite 数据变动 -> 生成 Tarball -> 发布到 NPM

3.4 消费层 (Hydration Layer - CLI)

支持 npm, yarn, pnpm 等主流包管理器。推荐使用 pnpm 以获得最佳的磁盘空间效率。

方式一:临时运行(无需安装)

bash
# 使用 pnpm dlx (推荐)
pnpm dlx @cndiv/cli hydrate --year 2025

# 或使用 npx
npx @cndiv/cli hydrate --year 2025

方式二:项目依赖(推荐)

bash
# 1. 安装 CLI 为开发依赖
pnpm add -D @cndiv/cli

# 2. 执行命令 (使用 bin alias 'cndiv')
pnpm exec cndiv hydrate --year 2025

技术实现细节 (Stream Pipeline)

typescript
// 伪代码:流式下载与解压
pipeline(
  got.stream(npmTarballUrl),   // 1. 下载流
  createGunzip(),              // 2. 解压流
  tar.extract()                // 3. 解包流
    .on('entry', (header, stream, next) => {
      if (header.name.endsWith('.csv')) {
         stream.pipe(sqliteImporter); // 4. 导入流
      }
      next();
    })
);

4. 社区治理与补丁协议 (The Patch Protocol)

为了解决"村级"数据的维护,必须建立类似于 Git 的数据版本控制机制,但作用于 SQLite 行级数据。

4.1 补丁文件结构

位于 Git 仓库的 patches/ 目录下。

json
// patches/2025/310115-pudong-update.json
{
  "meta": {
    "author": "github_user_id",
    "source_url": "http://example.gov.cn/notice.pdf",
    "apply_after": "2023-baseline"
  },
  "operations": [
    {
      "op": "add",
      "code": "310115001002",
      "name": "新设立社区居委会",
      "level": 5,
      "parent_code": "310115001"
    },
    {
      "op": "update",
      "code": "310115102",
      "status": "deprecated",
      "note": "撤销合并"
    }
  ]
}

4.2 验证流水线 (CI Pipeline)

当 Pull Request 包含 Patch 文件时,CI 触发校验:

  1. Schema Check:符合 @cndiv/data-protocol 定义
  2. Logic Check:父级代码是否存在?是否存在代码冲突?
  3. Conflict Check:是否与同年度的其他 Patch 冲突?

5. 迁移与兼容性策略

基于对现有源码(stats.gov.cn.js, gb2260.js)的深度分析,制定以下迁移计划。

5.1 遗留系统架构分析 (Legacy Analysis)

通过分析源码,现有系统主要包含两部分存储:

层级位置技术内容状态
缓存层../pageCacheDB/stats.gov.cnlevelup + leveldown (Google LevelDB)存储爬虫的 runHistory(运行记录)和原始 HTML/JSON 响应这是一个二进制数据库,依赖 Node.js C++ 绑定。由于它主要用于断点续传和缓存原始请求,不适合作为数据迁移的"真理源",除非我们需要回溯原始 HTML 来修复解析错误
发布层data/stats.gov.cn/*.jsondata/GB2260/*.json纯文本 JSON 文件makeCodeFile 函数生成的最终清洗数据,通常是按年份分割的树状结构或扁平列表这是目前对外服务的实际数据,应以此为迁移基准

5.2 迁移实施方案 (Migration Plan)

我们需要编写一个一次性迁移脚本 scripts/migrate-legacy-to-sqlite.ts,执行以下步骤:

Step 1: JSON 数据摄取 (Ingestion)

遍历 data/stats.gov.cn/ 下的所有年份 JSON 文件(如 2023.json)。

解析逻辑

  • 如果由 stats.gov.cn.js 生成,通常包含 urban_rural_code(城乡代码)
  • 这部分在 2024 年后架构中被标记为 legacy 字段
  • 将 JSON 树拍平为 (code, name, parent_code, level) 元组

Step 2: LevelDB 应急回溯 (Fallback)

仅在 JSON 数据缺失或损坏时启用。

编写辅助脚本使用 levelup 读取 pageCacheDB 中的 Keys。

注意:由于 leveldown 的原生依赖问题,此步骤建议在旧的 Docker 容器(Node 12/14)中运行,导出为中间态 JSON 后,再由主迁移脚本处理。

Step 3: SQLite 注入 (Injection)

将清洗后的数据批量插入新架构的 source-2023.db。为 2023 年及以前的数据打上:

  • source_type = 'official_nbs'
  • confidence_score = 100

Step 4: 仓库清理 (Cleanup)

确认 SQLite 数据库完整性后,执行 git filter-repo

移除

  • pageCacheDB/(LevelDB 二进制文件,体积巨大)
  • data/(旧 JSON)

保留:核心爬虫脚本(作为历史参考)和新的 Monorepo 结构

5.3 对下游的兼容

虽然内部架构巨变,但 CLI 仍需提供"传统格式导出"功能:

bash
# 导出为旧版 JSON 结构,以便老用户无缝切换
pnpm exec cndiv export --format legacy-json --year 2023 --out ./dist

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