# 元数据管线 — 开发规格 > 2026-07-19 --- ## 1. 需求概述 系统在启动和运行时,需要自动完成三个任务: | # | 任务 | 说明 | |---|------|------| | 1 | **新相册解析** | 扫描磁盘导入的新相册 → 提取人名+标签 → 写入 DB | | 2 | **老数据重解析** | 已有数据的相册用最新逻辑重新提取,强制覆盖 | | 3 | **人物合并** | 按中文核心合并同一人的不同记录 | 这三件事通过**同一个管道**完成,管道在**启动时跑一次** + **定时每 30 分钟跑一次**。 --- ## 2. 启动流程(时序) 当前问题:import 和 pipeline 是两个并发的 `tokio::spawn`,pipeline 固定等 3s,import 可能耗时更长,导致刚导入的相册没被解析。 **目标时序:** ``` 服务启动 │ ├── DB 初始化 │ ├─── 后台任务 A:启动管线(单次)─────┐ │ ├── ① 扫描导入新相册 │ │ ├── ② Phase 1:全量解析(强制覆盖) │ │ ├── ③ Phase 2:人物合并 │ │ └── ④ 刷新内存缓存 │ │ │ ├─── 后台任务 B:定时管线(每 30 分钟)──┤ │ ├── ① Phase 1:全量解析(强制覆盖) │ │ ├── ② Phase 2:人物合并 │ │ └── ③ 刷新内存缓存 │ │ │ └─── HTTP 服务启动 │ │ 注:后台任务 A 和 B 互斥,不会同时执行 ``` ### 变化要点 - **启动管线 = import + parse + merge + refreshCache** 依次串行 - **定时管线 = parse + merge + refreshCache**(不重复 import) - 管线内部顺序固定不可并发 --- ## 3. 管线内部结构 ``` run_pipeline(db, with_import: bool) │ ├── [with_import=true] 扫描导入新相册 │ ├── Phase 1:全量解析 │ for each album: │ ├── jieba 分词 → 候选人名 + 候选标签 │ ├── 人物库匹配 / jieba → 最佳人名 │ ├── 强制写入 albums.person_name_* + persons + aliases │ ├── 标签三步提取(词库→jieba→正则) │ ├── unique_tags(去重+排序+坏标签过滤) │ └── 强制写入 albums.tags + album_tags │ ├── Phase 2:人物合并 │ ├── 提取所有人名的中文核心 │ ├── 分组 → 每组选最多相册的为目标 │ └── 合并相册关联 / 别名,删除源 │ └── Phase 3:刷新缓存 └── 重新加载 albums 到 AlbumsCache ``` --- ## 4. 模块职责 | 模块 | 文件 | 职责 | |------|------|------| | Pipeline 引擎 | `engine/pipeline.rs` | `phase_parse_all()`、`phase_merge_persons()`、`run_pipeline()` | | 标题解析 | `engine/title_parser.rs` | jieba 分词、人名提取、中英文拆分、别名生成 | | 标签提取 | `engine/tag_extractor.rs` | 分类词库匹配、jieba 名词提取、标点/停用词/坏标签过滤 | | 人物合并 | `engine/person_merger.rs` | 中文核心提取、分组分析、合并执行 | | 导入 | `services/import.rs` | 扫描磁盘目录、创建相册和图片记录 | | DB | `db/metadata.rs` | persons、aliases、album_tags 表的读写 | | 缓存 | `cache/mod.rs` | AlbumsCache + TagCache + PersonCache | --- ## 5. 关键设计约束 1. **强制覆盖**:每次管线执行都是完整重解,直接覆盖 DB 数据 2. **幂等**:管线可反复执行,不影响正确性 3. **串行**:管线内部各阶段顺序执行,不并发 4. **多级过滤**:标签经过 5 层过滤才入库,确保质量 5. **中文优先**:人名优先中文,中英混杂拆为"主名+别名" 6. **纯中/纯英**:人名主体不允许中英混杂 --- ## 6. 实现清单 ### 6.1 Pipeline 引擎 - [x] `phase_parse_all()` — 全量解析 - [x] `phase_merge_persons()` — 人物合并 - [x] `phase_refresh_cache()` — 刷新缓存(在 main.rs 实现) - [x] `run_pipeline(db)` — 整合解析+合并 ### 6.2 main.rs 启动逻辑 - [x] 后台任务 A:顺序执行 import → run_pipeline → cache refresh - [x] 后台任务 B:定时每 30 分钟 run_pipeline → cache refresh ### 6.3 API - [x] POST /api/pipeline/run → 全量解析 + 人物合并