Note

把 PubMed XML 做成可更新的数据管道

从年度基线、增量更新、完整性校验到流式解析,整理一套适合本地检索与 AI 应用的 PubMed 数据工程思路。

目录
目录

2026 年 2 月,我整理过一份 PubMed XML 批量下载方案。最初目标是为本地文本处理准备结构化文献数据,但真正需要设计的并不是一条下载命令,而是一条能够校验、更新、重建和追踪版本的数据管道。

文件数量、容量和编号范围会随年度发布变化,实际执行时应以 NLM 当期目录及 README 为准。

为什么选择 XML,而不是从 PDF 开始

如果目标是题录检索、文献筛选或构建元数据索引,PubMed XML 已经提供了相对清晰的结构,包括 PMID、标题、摘要、作者、期刊、日期、出版类型和 MeSH 等字段。

与 PDF 相比,它有几个工程优势:

  • 不需要先解决版式解析和 OCR;
  • 可以按记录流式处理;
  • 字段来源和层级更明确;
  • 更容易做增量更新和删除记录处理;
  • 适合转换成数据库表或列式文件。

但 XML 结构化并不等于字段永远完整。标题中可能包含内联标记,摘要可能分段,日期可能只有年份或季节,作者也可能缺失部分姓名字段。解析程序必须允许不完整记录。

数据管道的七个阶段

我把完整流程拆成:

发现版本
→ 下载
→ 校验
→ 流式解析
→ 规范化
→ 存储与索引
→ 应用增量更新

每个阶段都应留下清单和日志,而不是把下载目录直接当成数据库。

1. 年度基线与增量文件分开保存

年度基线用于构建完整快照,updatefiles 用于加入新增、修订和删除记录。两者应进入不同目录:

pubmed/
├── source/
│   ├── baseline/
│   └── updatefiles/
├── manifests/
├── normalized/
├── index/
└── logs/

source/ 保存未经修改的下载文件;规范化结果和索引可以随时从源文件重建。

2. 下载前生成 manifest

manifest 至少记录:

  • 远端文件名与地址;
  • 文件所属发布批次;
  • 下载时间;
  • 本地文件大小;
  • 官方提供的校验信息;
  • 下载状态与重试次数;
  • 解析状态;
  • 解析程序版本。

这样才能区分“没有下载”“下载不完整”和“下载完成但解析失败”。

3. 完整性校验是下载流程的一部分

断点续传只能避免重复下载,不能证明文件内容正确。每个文件下载完成后,应使用发布方提供的校验信息进行验证;校验失败的文件不能进入解析队列。

批量任务还需要处理:

  • 临时文件与最终文件分离;
  • 校验成功后再原子改名;
  • 下载失败时限制重试次数;
  • 日志中记录 HTTP/FTP 状态与失败原因;
  • 再次运行时跳过已经验证的文件。

4. XML 应当流式解析

年度数据不适合一次性读入内存。更合适的方式是按 PubmedArticle 或相关记录节点迭代:

from lxml import etree

context = etree.iterparse(
    "pubmed.xml",
    events=("end",),
    tag="PubmedArticle",
)

for _, element in context:
    record = normalize_article(element)
    write_record(record)
    element.clear()

示意代码省略了解压、异常记录和父节点清理。真正运行时需要使用小文件测试内存是否稳定,并记录解析失败的 PMID 或源文件位置。

5. 先建立稳定的规范化层

在进入全文检索或向量库之前,我会先生成一套稳定记录:

pmid
record_version
record_status
title
abstract_sections
authors
journal
publication_date
publication_types
mesh_terms
source_file
ingested_at

复杂的作者、摘要分段和 MeSH 可以保留为子表或嵌套字段。关键是不要在第一版中为了“表格整齐”而丢掉原始结构。

6. 存储方式取决于查询方式

  • SQLite:适合单机原型、状态清单和中等规模元数据查询。
  • PostgreSQL:适合团队协作、事务更新和较复杂的检索服务。
  • Parquet:适合批量统计、机器学习数据准备和快照归档。
  • 全文搜索引擎:适合复杂关键词检索,但增加了部署与同步成本。

一个实用组合是:数据库维护当前记录和更新状态,Parquet 保存可复现快照;只有在需求明确后再增加向量索引。

7. 增量更新必须理解“删除”

更新文件不仅包含新增记录,也可能修订或删除既有 PMID。增量程序不能只做追加:

读取更新批次
→ 对新增或修改记录执行 upsert
→ 处理删除标记
→ 写入批次日志
→ 生成更新后的快照版本

每个快照都应能回答“包含到哪个更新批次”,否则后续检索结果无法复现。

不要直接把原始 XML 倒进 RAG

在建立向量索引之前,至少要解决:

  • 重复和修订记录;
  • 空摘要与分段摘要;
  • 文本语言;
  • 标题中的内联标记;
  • 检索单元与 PMID 的稳定关联;
  • 重新嵌入时的版本管理;
  • 来源展示与数据使用边界。

向量库只是检索层,不应承担数据清洗和版本控制。

使用边界

PubMed 数据的不同字段和关联资源可能有不同使用要求。公开服务或再分发前,应核对当期 NLM README、DTD 文档和相关条款,注明数据来源,不使用官方标识暗示背书。

参考入口:

建议阅读

讨论

评论使用 GitHub Discussions。首次加载需要访问 GitHub。