# 数据库表结构文档 > 数据库:SQLite(`data/app.db`,WAL 模式) > 最后更新:2026-08-28(词根维度 + 搜索功能版本) > 表结构维护方式:启动时 `CREATE TABLE IF NOT EXISTS` 自动建表 + 代码内增量迁移(`ALTER TABLE`),无需手工执行 SQL ## 总览 系统按三个维度存储学习数据: | 表 | 维度 | 说明 | |---|---|---| | `history` | 查询次数 | 每次查询的原句与完整结果快照 | | `words` | 单词 | 跨查询累积的单词档案(释义、词根拆解、原句记录) | | `roots` | 词根 | 跨单词累积的词根档案(哪些学过的词包含它、各词中体现的含义) | ### 维度间关系 ``` history (一次查询) │ 查询完成后自动触发 ▼ words (每词一行) ──写入时同步──▶ roots (每词根一行) ``` - `words.word` 唯一;`roots.root`(规范化键)唯一 - 同一单词在 `roots` 下仅保留一条映射(重新拆解时旧映射自动摘除) --- ## 1. history — 查询历史(按次记录) | 列 | 类型 | 约束 | 说明 | |---|---|---|---| | `id` | INTEGER | PK, AUTOINCREMENT | 记录 ID | | `sentence` | TEXT | NOT NULL | 用户粘贴的原句 | | `words` | TEXT | NOT NULL | 查询的单词列表,JSON 数组:`["analysis", "analyze"]` | | `result` | TEXT | NOT NULL | LLM 结构化结果快照,见下方 JSON 结构 | | `raw_result` | TEXT | 可空 | LLM 原始输出(排查用) | | `created_at` / `updated_at` | TEXT | NOT NULL | 本地时间,写入/最后编辑时间 | ### `result` JSON 结构 ```json { "sentence_translation": "整个原句的中文翻译", "words": [ { "word": "analysis", "phonetic": "/əˈnæləsɪs/", "roots": [ { "part": "ana-", "type": "前缀", "phonetic": "/əˈnæ/", "meaning": "向上、全面" } ], "context_sense_id": 0, "context_sense": "n. 分析;解析", "context_examples": [ { "en": "English sentence.", "zh": "中文翻译" } ], "other_senses": [ { "sense_id": -1, "sense": "n. 化验", "examples": [ { "en": "...", "zh": "..." } ] } ] } ] } ``` - `context_sense_id`:本次语境命中的词库已有释义编号(0 起),`-1` 表示新释义 - `roots[].type`:前缀 / 词根 / 后缀 / 音节 - 已编辑的历史记录中 `roots` 支持手工维护(编辑界面按 `部分 | 类型 | 音标 | 含义` 行格式) --- ## 2. words — 词库(按单词维度,跨查询累积) | 列 | 类型 | 约束 | 说明 | |---|---|---|---| | `id` | INTEGER | PK, AUTOINCREMENT | | | `word` | TEXT | NOT NULL, **UNIQUE**(自动索引) | 单词小写形式 | | `phonetic` | TEXT | | 整词美式音标 | | `roots` | TEXT | NOT NULL, 默认 `'[]'` | 词根拆解,JSON:`[{part, type, phonetic, meaning}]` | | `senses` | TEXT | NOT NULL, 默认 `'[]'` | 释义累积,见下方 | | `root_keys` | TEXT | NOT NULL, 默认 `'[]'` | 该词当前映射到的词根规范化键,如 `["ana","naly","sis"]` | | `search_text` | TEXT | NOT NULL, 默认 `''` | 检索文本(见下) | | `created_at` / `updated_at` | TEXT | NOT NULL | | ### `senses` JSON 结构 ```json [ { "sense": "n. 分析;解析", "examples": [ { "en": "原句本身", "zh": "原句翻译", "from_sentence": true }, { "en": "AI 生成的同义例句", "zh": "翻译" } ] } ] ``` - 同义义项合并规则:新查询语境命中已有义项(`context_sense_id`)→ 追加"原句 + 本次生成的同义例句";新语境 → 新增义项 - 例句按英文原文去重;`from_sentence: true` 标记来自真实原句(前端以 📌 展示) ### `search_text`(检索列) 内容 = `单词 + 各义项标题 + 词根 part/规范化键/含义`,统一小写。 **刻意不含例句正文**,避免例句里的无关词(如 "company" 含 "any")干扰检索。由 `buildWordSearchText()` 生成,在写入与启动迁移时刷新。 --- ## 3. roots — 词根库(按词根维度,跨单词累积) | 列 | 类型 | 约束 | 说明 | |---|---|---|---| | `id` | INTEGER | PK, AUTOINCREMENT | | | `root` | TEXT | NOT NULL, **UNIQUE**(自动索引) | 规范化键:去连字符/非字母、小写,如 `lysis` | | `display` | TEXT | NOT NULL | 展示形(保留连字符),如 `-tion`,以最近出现为准 | | `type` | TEXT | | 前缀 / 词根 / 后缀 / 音节 | | `phonetic` | TEXT | | 词根发音(IPA) | | `words` | TEXT | NOT NULL, 默认 `'[]'` | 包含该词根的已学词,见下方 | | `created_at` / `updated_at` | TEXT | NOT NULL | | ### `words` JSON 结构 ```json [ { "word": "analysis", "phonetic": "/əˈnæləsɪs/", "meaning": "松开、解开", "word_senses": ["n. 分析;解析", "n. 分解;剖析"] } ] ``` - `meaning`:该词根**在此词中**体现的含义——刻意不做全局统一,多个词的含义变体并列展示,供学习者自行抽象 - `word_senses`:该单词自身的释义列表(词根面板点击单词揭晓时一并展示) - 同一单词重复查询时条目整体覆盖;单词重新拆解后,从不再包含它的旧词根下自动摘除(词根下无词时整行删除) --- ## 4. 合并/维护逻辑(写入路径) 查询完成(流式返回 done 前)按顺序执行: 1. `upsertWordData(wordResult, sentence, sentenceTranslation)` - 释义合并:`context_sense_id` 命中 → 并入原句 + 同义例句;否则新增义项 - `other_senses`:文案相同 → 例句并入已有义项;否则新增 - 词根同步:为 `roots` 中每个部分调用 `upsertRootData`,并按 `root_keys` 清理旧映射 - 刷新 `search_text` 2. `saveRecord(...)` 写入 `history` ## 5. 启动时自动迁移 - `words.root_keys`、`words.search_text`:缺失时 `ALTER TABLE` 补列 - `search_text` 每次启动对全表回填 - 历史版本说明:v1 仅 `history` 表;"按单词维度"版本引入 `words`(破坏性变更,经确认清除旧数据);当前版本追加 `roots` ## 6. 相关 API | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/history?page=&size=&q=` | 历史分页列表,`q` 搜原句/单词 | | GET | `/api/history/:id` | 历史详情 | | PUT | `/api/history/:id` | 编辑保存 | | DELETE | `/api/history/:id` | 删除 | | GET | `/api/words?page=&size=&q=` | 词库分页列表,`q` 搜单词/释义/词根(不含例句) | | GET | `/api/words/:word` | 单词档案 | | GET | `/api/roots/:root` | 词根档案(键为规范化形式) | | POST | `/api/query/stream` | 流式查询(写入全部三表) |