arXiv ID 格式

当前内容契约更新:固定来源 PDF 已恢复为 paper_access 开关下的鉴权字节, 关闭404,qa_、别名、Range、历史原件不能绕过。新内容在独立 qatlas-content 桶的 content/ 命名空间不可变发布:source 绑定确切 PDF SHA,arXiv vN 是语义版本、 S3VersionId 是物理版本、parse revision 是独立不可变身份;三者不可混用。 同 paper/SHA 可复用 source;冻结导入别名不同字节409(overwrite也不替换)。 解析上传必须完整支持的 Middle+Markdown,保留所有成员原名/字节,MD-only拒收; manifest最后核验发布且PG必需,重传新revision,不覆盖历史。旧MD/JSON/images忽略, 只在内容/PDF访问按需冻结旧PDF,不bulk回填、不删除旧桶;没有nightly/boot/入库自动推理。 下文涉及旧三桶覆盖、仅full.md+images、原PDF410/外部直链的段落保留为历史背景, 不作为当前操作规则。当前API/上传/续读统一见论文内容契约 与Upload API;完整read视图不是原Middle JSON。

QuantumAtlas 以 arXiv ID 为论文的主键。文本侧支持两种 ID 格式 + 版本后缀;存 储侧把每条 ID 拆成「年月分片 / 子领域 / 文件 stem」三段做 sharding。本文档讲 完整规则,包括 2026-06 引入的按子领域分目录新布局以及背后的根因。

1. 两种格式

时代

格式

例子

老式(≤ 2007-03)

<category>/<7-digit>

quant-ph/9508027、hep-th/0207001、cs.AI/0101001、physics.atom-ph/0001001

新式(2007-04 起)

<YYMM>.<4–6-digit>

2501.00010、2403.12345、2401.123456

注意 老式 ID 的 category 含斜杠,所以会出现在 URL path 里。server 端 splitPapersPath 按"最后一段"匹配 action / arxiv_id 切分能正确处理。

1.1 老式 category 词表

支持的 category 形态(按 internal/paperassets::oldStyleCategoryRE 实现的语法):

形态

例子

说明

无子分类

quant-ph、hep-th、gr-qc、math-ph

主题字段为 lower-case,可含 -

大写 2 字母子分类

cs.AI、math.AG、q-bio.NC、nlin.CD

子字段 \.[A-Z]{2}

小写连字符子分类

physics.atom-ph、cond-mat.stat-mech

子字段 \.[a-z][a-z\-]*

A1 之前的正则只覆盖前两种,碰到 physics.atom-ph/0001001v1 这类直接 reject。 现在统一收下。

2. 版本后缀 vN

任何 arXiv 论文都可以有多个版本(v1、v2、...)。

入口

是否要求 vN

qatlas ingest <id>

可不带;server 取 arXiv 当前最新版

qatlas contrib pdf <id>

必填;对象寻址按 <id>v<n> 命名

qatlas contrib mineru <id>

必填

GET /api/papers/{id}/markdown(及 images 等)

可不带;server 优先查本地 catalog 补最新版本,未收录才抓 arxiv.org(多版本时在响应里显式标)

GET /api/papers/{id}/pdf

鉴权固定来源PDF字节,source_id或语义version互斥,开关禁用404、Range同样鉴权;不需解析token

论文详情 GET /api/papers/{id} 与各资产端点还接受 qa_ paper_id(服务端 解析成该论文的 canonical 身份,取最高已收录的 arXiv 版本;DOI-only 论文走 DOI 管线)。

3. 对象寻址映射(post-A1 layout)

server 把 ID 拆成 <YYMM-shard>/<可选 category>/<stem>.<ext>:

arxiv_id

object key(PDF)

说明

2501.00010v1

pdf/2501/2501.00010v1.pdf

新式扁平

2403.12345v2

pdf/2403/2403.12345v2.pdf

新式扁平

quant-ph/9508027v1

pdf/9508/quant-ph/9508027v1.pdf

老式带子目录

hep-th/0207001v3

pdf/0207/hep-th/0207001v3.pdf

老式带子目录

cs.AI/0101001v1

pdf/0101/cs.AI/0101001v1.pdf

含子分类的老式

md/ / json/ / images/ 子目录采用同样的三段布局(kind + shard + 可选 category + stem)。完整规则在 internal/paperassets/path.go::AssetKeyFor。

<YYMM> 跟 arxiv.org bulk-data 目录约定 一致。 带 category 子目录是 QuantumAtlas 在 A1(2026-06)后引入的额外维度,bulk-data 上游 没有这一层 —— 我们引入它是为了避免下一节描述的跨子领域冲突。

3.1 为什么老式 ID 要保留 category 子目录

老式 7-digit number 不是全局唯一的,只在 category 内唯一。同一个 YYMMnnn 在不同 category 下对应完全不同的论文:

arxiv URL

标题

arxiv.org/abs/quant-ph/0207065

Relation between classical communication capacity and entanglement capability for two-qubit unitary operations

arxiv.org/abs/hep-th/0207065

Does curvature-dilaton coupling with Kalb Ramond field lead to an accelerating Universe?

arxiv.org/abs/math/0207065

A duality proof of Tchakaloff's theorem

arxiv.org/abs/gr-qc/0207065

Gravitomagnetic effects

剥掉 category 后写到同一个 bucket key(pdf/0207/0207065v1.pdf)= silent overwrite。A1 之前确实是这么存的;当前生产之所以没踩,纯粹是因为 OpenAlex bootstrap 加了 quant-only filter。一旦扩到 hep-th / cond-mat 等任意第二个子领域, 立刻冲突。

A1 的 pdf/<yymm>/<category>/<stem>.<ext> 子目录布局从结构上彻底排除这种冲突。

3.2 新旧布局对照

arxiv_id

A1 之前(legacy)

A1 之后(new)

2501.00010v1

pdf/2501/2501.00010v1.pdf

pdf/2501/2501.00010v1.pdf (unchanged)

quant-ph/9508027v1

pdf/9508/9508027v1.pdf

pdf/9508/quant-ph/9508027v1.pdf

hep-th/0207065v1

pdf/0207/0207065v1.pdf(冲突!)

pdf/0207/hep-th/0207065v1.pdf

新式 ID 的 layout 不变(数字本来就全局唯一)。仅老式有变更。

3.3 Dual-read 过渡期

A1 后立刻部署 server 不会 break 已有数据:

  • 读路径 (paperassets.LocateAsset / LocateAssetByID) 先查新 layout,未命中 时对老式 canonical ID 回退查 legacy bare key

  • 写路径 (AssetKey / AssetKeyFor) 总是写新 layout,不写 legacy

也就是说:

  • 老对象(pre-A1,bare layout)→ 通过 fallback 仍可读

  • 新写入(post-A1)→ 都进 per-category 子目录

  • migration 把 legacy 对象 mc cp 到新位置(manifest-based,三阶段;plan §4 Phase E)→ 同步更新 catalog 主键

  • 一个 release 后移除 dual-read fallback 路径

dual-read 命中由 paperassets.LegacyLayoutReads() 计数,运维可观测 migration 进度。

4. kind 后缀

每篇论文除了 PDF 还可能有:

kind

key 模板(新式)

key 模板(老式 canonical)

内容

pdf

pdf/<yymm>/<stem>.pdf

pdf/<yymm>/<category>/<stem>.pdf

原始 PDF

markdown

markdown/<yymm>/<stem>.md

markdown/<yymm>/<category>/<stem>.md

MinerU 解析的 markdown

json

json/<yymm>/<stem>.json

json/<yymm>/<category>/<stem>.json

arXiv 元数据(题目 / 作者 / abstract)

images

images/<yymm>/<stem>.zip

images/<yymm>/<category>/<stem>.zip

MinerU 解析出的图片 zip

qatlas contrib pdf --pdf 把 PDF 字节落到 pdf/。论文元数据(题目 / 作者 / 摘要 / 引用)走 OpenAlex 上游同步进 PostgreSQL paper registry,不再通过 upload 端点写 json/(v0.7.0 起;该前缀仅保留兼容历史对象的读路径)。

5. 规范化与结构化解析

internal/paperassets 提供两层 API:

  • 轻量 helpers(保留兼容历史调用方):

    • NormalizeIdentifier(s) — 去空白 + 剥 arXiv: 前缀

    • StripVersion(s) — 去掉尾部 vN

    • SafeKey(s) — 把 / 换成 __ 给老式磁盘 fallback 用

  • 结构化解析(新代码优先用):

    • Parse(s) (ParsedArxivID, error) — 拆成 Category / Stem / StemBase / Version / YYMM 等字段

    • MustParse(s) — 测试常量用,invalid 输入直接 panic

    • AssetKeyFor(kind, p) — 给 ParsedArxivID 渲染对象 key

    • LegacyAssetKeyFor(kind, p) — 给 dual-read fallback 用的 pre-A1 key

    • LocateAsset(ctx, store, kind, p) — 一站式 read 接口:自动新 layout 优先 + legacy fallback

老式 bare ID(9508027v1,无 category)由 Parse 标记 IsBare=true,调用方决 定怎么处理:

  • upload 入口 (ValidateUploadID):当前仍兼容接受 bare(issue #4 缓解)

  • storage 入口 (AssetKeyFor):bare 输入回退到 legacy layout pdf/<yymm>/<stem>.<ext>

  • 未来(plan §H3 / issue #12):catalog migration 完成后 ValidateUploadID 拒 bare,由上层 resolver 反查 registry 拿到 category 再调用

6. 常见坑

upload 时漏掉 v1

qatlas contrib pdf 2501.00010 --pdf paper.pdf

server 返回 400 arxiv_id must include version suffix。改成 2501.00010v1。

用了 arxiv.org/abs/... 完整 URL

server 只接受 ID 部分。从 URL https://arxiv.org/abs/2501.00010 抽出 2501.00010 就行。

老式带版本是合法的

quant-ph/9508027v1(含斜杠 + 版本)—— 是合法的,正常工作。

老式 bare 形态(9508027v1,无 category)当前仍接受但有歧义

由 issue #4 历史原因,server ValidateUploadID 仍兼容裸形态。但裸 7-digit 号在不同子 领域下指向不同论文(见 §3.1);当前仅靠"catalog 只有 quant-ph"这个事 实保证不冲突。新代码 / 客户端建议永远带 category 前缀调用。 issue #12 跟踪 最终拒绝裸形态的工作。

DOI 入口同一个端点

GET /api/papers/{id_or_doi}/markdown 自动 detect DOI(^10\.\d{4,9}/), 经 OpenAlex 反查成 arxiv_id 后走同一套 handler。详见 REST API · DOI 寻址。