# 统一数据库架构设计文档 (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 只需要专注于**业务逻辑**和**接口定义**,数据库部分直接指向这份文档即可。这样不仅结构清晰,而且保证了技术实现的一致性。