125 lines
4.5 KiB
Markdown
125 lines
4.5 KiB
Markdown
# 元数据管线 — 开发规格
|
||
|
||
> 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 → 全量解析 + 人物合并
|