note/app_prd/统一数据库架构设计文档SQL.md

218 lines
8.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 统一数据库架构设计文档 (Unified Database Schema)
| 文档版本 | V1.0 |
| :--- | :--- |
| **最后更新** | 2025-12-09 |
| **适用范围** | UDC-M (模块一), QPES (模块二), KES (模块三) |
| **技术选型** | PostgreSQL 14+, SQLModel (ORM) |
---
## 1. 设计概述
本数据库旨在支撑“文档解析 -> 题目提取 -> 知识增强”的全链路数据流转。
### 1.1 核心实体关系 (ERD 简述)
* **Documents (1) : (N) Conversion Tasks**
* 一个文档可以被多次转换(如转 MD, 转 PDF
* **Documents (1) : (N) Questions**
* 一个文档包含多道题目。
* **Documents (1) : (N) Extraction Tasks**
* 一个文档可以被多次提取(如调整 Prompt 后重试)。
### 1.2 关键数据类型
* **UUID**: 所有核心业务主键使用 UUID方便分布式生成和迁移。
* **JSONB**: 充分利用 PostgreSQL 的 JSONB 能力存储非结构化数据(选项、知识点数组、图片链接),支持索引查询。
---
## 2. 详细表结构定义
### 2.1 基础资产层 (Module 1: UDC-M)
#### Table: `documents` (文档资产表)
这是系统的根表,记录所有上传的原始文件。
```sql
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- 文件元数据
filename VARCHAR(255) NOT NULL, -- 原始文件名
file_hash VARCHAR(64) NOT NULL UNIQUE, -- SHA256用于秒传去重
file_size BIGINT, -- 文件大小 (Bytes)
file_type VARCHAR(16), -- 扩展名: pdf, docx, xlsx
storage_path VARCHAR(512) NOT NULL, -- MinIO 永久存储路径 (udc-raw/...)
-- 业务元数据
tags JSONB, -- 标签: {"subject": "math", "year": 2024}
uploader_id BIGINT, -- 上传用户ID
-- 转换状态缓存 (指向最新的 Markdown 结果)
markdown_status VARCHAR(32) DEFAULT 'none', -- none, processing, success, failed
markdown_url VARCHAR(512), -- 解析后的 Markdown MinIO 地址
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_docs_hash ON documents(file_hash);
CREATE INDEX idx_docs_created ON documents(created_at);
```
#### Table: `conversion_tasks` (转换流水记录)
记录 UDC 服务的每次转换操作。
```sql
CREATE TABLE conversion_tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
document_id UUID REFERENCES documents(id) ON DELETE CASCADE,
target_format VARCHAR(16) NOT NULL, -- markdown, pdf, docx
output_mode VARCHAR(16) DEFAULT 'url', -- url, archive
status VARCHAR(32) NOT NULL, -- queued, processing, success, failed
result_url VARCHAR(512), -- 结果文件下载地址
error_msg TEXT, -- 错误日志
config_snapshot(JSONB), -- 记录当时转换时的参数 template_id, force_ocr, chunk_size 方便排错。
-- 性能指标
worker_node VARCHAR(64), -- 处理该任务的 Worker 节点名
process_duration_ms INT, -- 处理耗时
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP
);
```
---
### 2.2 题目数据层 (Module 2 & 3: QPES & KES)
#### Table: `questions` (核心题库表)
这张表是 Module 2 (Insert) 和 Module 3 (Update) 的协作点。
```sql
CREATE TABLE questions (
id BIGSERIAL PRIMARY KEY, -- 题目自增ID (用于对外展示更短)
uid UUID DEFAULT gen_random_uuid(), -- 内部唯一标识
-- 关联
document_id UUID REFERENCES documents(id) ON DELETE CASCADE,
extraction_task_id UUID, -- 关联是哪次任务提取出来的
question_seq INT, -- 题目在原卷中的顺序
-- ==========================================
-- Module 2 写入 (内容提取)
-- ==========================================
question_type VARCHAR(32), -- choice, fill, essay, unknown
content_md TEXT NOT NULL, -- 题干 (Markdown + LaTeX + MinIO URL)
options_json JSONB, -- 选项 (仅选择题): [{"label":"A", "text":"..."}, ...]
answer_md TEXT, -- 参考答案
analysis_md TEXT, -- 解析
image_urls JSONB, -- 冗余字段: ["http://minio.../1.jpg"] 方便索引包含图片的题
content_hash VARCHAR(64), -- MD5(content_md),用于文档内或跨文档去重
-- ==========================================
-- Module 3 写入 (知识增强)
-- ==========================================
-- 机器自动提取部分
problem_summary TEXT, -- 摘要
knowledges JSONB, -- ["知识点1", "知识点2"]
methods JSONB, -- ["方法1", "方法2"]
-- 人工审核部分 (应用层展示以此为准)
updated_knowledges JSONB,
updated_methods JSONB,
-- 状态流转
enrich_status VARCHAR(32) DEFAULT 'pending', -- pending -> processing -> done / failed
enrich_error TEXT,
is_reviewed BOOLEAN DEFAULT FALSE, -- 是否人工审核过
reviewer_id BIGINT,
reviewed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 索引
CREATE INDEX idx_q_doc ON questions(document_id);
CREATE INDEX idx_q_enrich_status ON questions(enrich_status) WHERE enrich_status = 'pending'; -- 任务队列轮询优化
CREATE INDEX idx_q_knowledges ON questions USING GIN (knowledges); -- 支持 JSON 数组搜索
CREATE INDEX idx_q_hash ON questions(content_hash);
CREATE INDEX idx_q_is_reviewed ON questions(is_reviewed); -- (方便 KES 过滤保护)。
```
#### Table: `extraction_tasks` (提取任务记录)
记录 LLM 提取的消耗。
```sql
CREATE TABLE extraction_tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
document_id UUID REFERENCES documents(id),
model_name VARCHAR(64), -- e.g., deepseek-v3
chunk_strategy VARCHAR(64), -- e.g., sliding-window-3000
total_tokens INT, -- 消耗 Token 数
questions_count INT, -- 提取出的题目数量
status VARCHAR(32), -- processing, success, failed
error_log TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
---
### 2.3 辅助字典层 (Module 3 Optional)
#### Table: `knowledge_tree` (知识点树 - 选做)
用于规范化 Module 3 的打标结果,避免 AI 生成“勾股定理”和“毕达哥拉斯定理”这种同义词导致检索分裂。
```sql
CREATE TABLE knowledge_tree (
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL,
parent_id INT REFERENCES knowledge_tree(id),
subject VARCHAR(32), -- math, physics
level VARCHAR(32), -- primary, middle, high
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
---
## 3. 数据流转状态机 (State Machine)
### 3.1 `documents.latest_parse_status`
* `none`: 刚上传,未处理。
* `processing`: UDC 正在转换中。
* `success`: 转换完成,`latest_result_url` 有值Markdown可用
* `failed`: 转换失败。
### 3.2 `questions.enrich_status`
* `pending`: 题目刚被 Module 2 插入,等待打标。
* `processing`: Module 3 正在调用 API。
* `done`: 机器打标成功。
* `failed`: 外部 API 调用失败(需重试)。
---
## 4. 开发注意事项
1. **JSONB 兼容性**: 在 Python 中使用 SQLModel 定义 JSONB 字段时,需要使用 `sa_column=Column(JSON)`
2. **事务控制**:
* Module 2 在写入 `questions` 时,建议开启事务:如果一道题写入失败,整个 Batch 回滚,或者记录错误日志但不中断其他题目。
3. **并发锁**:
* Module 3 在领取任务时(`SELECT * FROM questions WHERE enrich_status='pending' LIMIT 10`),建议使用 `FOR UPDATE SKIP LOCKED`,防止多个 Worker 抢同一个题目造成重复调用 API 浪费钱。
---
现在,你的三个 PRD 只需要专注于**业务逻辑**和**接口定义**,数据库部分直接指向这份文档即可。这样不仅结构清晰,而且保证了技术实现的一致性。