# 数据流:论文从 arXiv 到可检索资产 > **当前内容契约更新**:固定来源 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/上传/续读统一见[论文内容契约](../server/paper-content.md) > 与[Upload API](../server/upload-api.md);完整read视图不是原Middle JSON。 这张图是 QuantumAtlas 端到端的「主线剧情」。每个箭头都对应一个真实的 CLI 命令或 server 操作。 ```{mermaid} flowchart TB subgraph SRC ["外部源"] ARX[arXiv] OTH[其他来源
本地 PDF] OA[OpenAlex] PUB[出版社 / OA 仓库
DOI 落地页] end subgraph STORE ["对象存储(不可变资产)"] PDF[PDF
pdf/<yymm>/<id>v<n>.pdf] MD[Markdown
md/<yymm>/<id>v<n>.md] IMG[images/] end subgraph PG ["PostgreSQL(registry + corpus)"] REG[paper registry
papers / paper_assets / paper_identities] CORP[OpenAlex corpus
openalex_works] end subgraph SEARCH ["搜索引擎"] ENG[POST /api/search
catalog / arxiv / openalex] end ARX -->|qatlas ingest| PDF OTH -->|qatlas contrib pdf| PDF PUB -->|Robust Downloader| PDF PDF -->|MinerU| MD PDF -->|MinerU| IMG PDF & MD & IMG -->|register| REG OA -->|qatlasd openalex bootstrap-pg| CORP REG & CORP --> ENG ARX & OA --> ENG style STORE fill:#e3f2fd,stroke:#1976d2 style PG fill:#e8f5e9,stroke:#388e3c style SEARCH fill:#fff3e0,stroke:#f57c00 ``` ## 四种获取路径 数据可以从四个地方进入资产层。**最终的保存路径都一样**(`/pdf//v.pdf` 等,S3 后端时是对应 bucket 里的对象 key),区别只是触发者: ### 1. 服务器自动抓取(arXiv) ```bash qatlas ingest quant-ph/9508027 --parser mineru ``` server 调 arXiv API 抓 PDF + metadata,可选立刻调 MinerU 解析。**触发方需要 `papers:write` scope**。 ### 2. 用户直接上传 ```bash qatlas contrib pdf 2501.00010v1 --pdf paper.pdf ``` 适合:手里已经有 PDF(公司内部论文、扫描件、preprint 私下流传版本)。**需要 `papers:write` scope**。 ### 3. 用户本地跑 MinerU 推回 ```bash # 配 mineru_api_tokens 后 qatlas contrib mineru 2501.00010v1 --push-pdf # 或队列模式,处理 server 列表里所有待解析的 qatlas contrib mineru --batch-size 20 ``` 本地用自己的 MinerU 配额跑解析。**server 颁发 30 分钟原子 claim**——多个贡献者并发跑不会撞重。需要 `papers:write` scope。 ### 4. Robust Downloader(DOI / 正式版批量抓取) ```text POST /api/downloader/fetch {"items": ["10.1038/s41586-024-07806-9", "arXiv:2401.12345"]} ``` 给 DOI / arXiv id / 论文 URL(单批 ≤50 条),server 跑多范式策略阶梯 (arXiv 直下 → OpenAlex twin → OA 元数据 API → 出版社 URL 模板 → 落地页 挖掘 → 浏览器 lane / LLM 兜底 / 远端代理)抓**正式版 PDF**,统一验证后 入库并驱动 MinerU。SPA 页面 `/$lang/downloader`。与前两条路径的区别: **来源不限于 arXiv**——绿色 OA 仓库、出版社模式 URL、需要 entitlement 的 落地页都在射程内。需要 `papers:write`(提交)/ `papers:read`(查 job)scope。 详见 [上传论文资产](../client/upload-assets.md)、[用 MinerU 解析](../client/parse-with-mineru.md) 和 [Robust Downloader](../server/downloader.md)。 ## 懒加载摄入(lazy ingest) `GET /api/papers/{id_or_doi}/markdown`(仅当部署方开启 `QATLAS_PAPER_ACCESS_ENABLED`;历史PDF410说明已被不可变内容契约替代;当前`/pdf`按gate鉴权交付,旧图中PDF抓取是 markdown 管线的内部阶段)在缓存未命中时**不阻塞**:server 立即返回 202 + `Operation-Location`,后台静默从 arxiv.org fetch PDF 并串 MinerU 转换, 客户端轮询 `/markdown/status` 直到 `state == cached` 再 GET 拿字节。同一篇 论文的 N 个并发请求被 server-side dedupe 成 1 次 fetch + 1 次 convert。完整协议见 [REST API · 长任务](../server/rest-api.md)。 ## Registry 写入路径 ```text 1. PUT s3://qatlas-pdf//.pdf ← 字节先落对象存储 2. INSERT ... ON CONFLICT papers + paper_assets ← PostgreSQL registry 同步 3. PostgreSQL 不可用时:HTTP 仍成功 + X-Catalog-Sync: deferred 4. 之后跑 qatlasd papers sync --full --from-rustfs 从对象存储重建缺失状态 ``` 对象存储是资产字节的 source of truth;PostgreSQL 是可重建的集合索引与租约层。 ## 搜索路径 搜索只登记论文元数据,不自动下载 PDF,也不把新命中标为待下载。普通、逐平台、Agentic 和自定义评分搜索都遵循同一策略。用户在结果中勾选论文并点击「下载所选」后,前端才调用 `POST /api/downloader/fetch`,由主服务为明确选择的条目提交任务;worker 的领取与执行方式不变。升级前已有的排队任务不会自动取消。 `POST /api/search` 接收一个 SearchEntry JSON,engine 按 config.yaml 的 `search.providers`(默认 `catalog,arxiv,openalex`)fan-out: - **catalog**:本地 PostgreSQL registry 的元数据 + 资产状态; - **arxiv / openalex**:上游在线查询(建议配 `paper_access.openalex_mailto` 进 polite pool)。 `search.remote` 启用后另有 `POST /api/search/multi`:逐平台(backend)返回 **原始**命中列表,不做跨源融合——SPA 的 backend picker + 每平台 Tab 渲染 就是这条路径(见 [REST API · Search](../server/rest-api.md))。 语义向量检索不在 `/api/search` 的 provider 列表里:它由独立的 qatlas-rag 微服务提供(dense+sparse 混合检索,RRF + rerank),经 qatlas-search 作为 fan-out 的一个 backend 接入;qatlasd 在论文 ready 时向 qatlas-rag 推送 索引(config.yaml 的 `rag.remote` 段)。 ## 关键不变量 ```{admonition} 记住这几条 :class: note - **对象存储是证据**,几乎不改,可追溯; - **PostgreSQL 是 registry**,可重建、可 SQL 查询;冲突时以对象存储为准; - **搜索是派生视图**,provider 可增删,不持有独立事实。 ``` 理解这三条就能理解 90% 的设计决定。