|
| 1 | +# MFSL 数据库架构升级设计 |
| 2 | + |
| 3 | +> 确认日期:2026-03-23 |
| 4 | +> 状态:已确认(5 段设计全部通过用户审批) |
| 5 | +
|
| 6 | +## 背景与动机 |
| 7 | + |
| 8 | +### 现有架构问题 |
| 9 | + |
| 10 | +1. **标签断层**:7 维标签只存在于 registry.csv(库文件级别,50 行),化合物级别(96 万条)完全没有标签。用户选"只搜 PFAS"时无法精确到化合物。 |
| 11 | +2. **Level 3 命名误导**:`level3_compounds.csv` 名字暗示它只用于 Level 3 匹配,但实际上所有 Level 匹配后都需要查询化合物属性。 |
| 12 | +3. **质谱库谱图缺 InChIKey**:8.3%(55,636 条)谱图无 InChIKey,无法关联到化合物元数据。 |
| 13 | +4. **环境非靶向标签缺失**:无法按 PFAS/农药/监管清单等维度过滤搜索。 |
| 14 | + |
| 15 | +### 升级目标 |
| 16 | + |
| 17 | +- 建立统一化合物元数据表,用 InChIKey 关联所有 Level |
| 18 | +- 每个化合物拥有完整标签(化合物级 4 维 + 谱图级 3 维) |
| 19 | +- 支持环境非靶向筛查的标签过滤 |
| 20 | +- 补全质谱库谱图的 InChIKey 覆盖率 |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## 1. 双库架构 |
| 25 | + |
| 26 | +MFSL 由两个核心库组成,通过 InChIKey 关联: |
| 27 | + |
| 28 | +``` |
| 29 | +┌─────────────────────────────────┐ InChIKey ┌──────────────────────────────────┐ |
| 30 | +│ 质谱库 (Spectral DB) │ ◄──────────────► │ 化合物元数据库 (Compound DB) │ |
| 31 | +│ │ │ │ |
| 32 | +│ 存储:deduplicated/*.msp │ │ 存储:compound_metadata.csv │ |
| 33 | +│ 内容:57.9 万条 MS2 谱图 │ │ 内容:96.1 万条化合物 │ |
| 34 | +│ 每条:InChIKey + peaks + │ │ 每条:InChIKey + 基础属性 + │ |
| 35 | +│ PrecursorMZ + metadata │ │ 4 维标签 + 交叉引用 │ |
| 36 | +│ 用途:Level 2 MS2 谱图匹配 │ │ 用途:Level 3 MS1 匹配 + │ |
| 37 | +│ │ │ 所有 Level 的属性查询 │ |
| 38 | +│ 谱图级标签(3 维): │ │ │ |
| 39 | +│ confidence (experimental/ │ │ 化合物级标签(4 维): │ |
| 40 | +│ predicted) │ │ chemical_class │ |
| 41 | +│ instrument (orbitrap/qtof..) │ │ application │ |
| 42 | +│ polarity (pos/neg) │ │ sample │ |
| 43 | +│ │ │ reg_lists │ |
| 44 | +└─────────────────────────────────┘ └──────────────────────────────────┘ |
| 45 | +
|
| 46 | +registry.csv = 来源管理清单(记录 MSP 文件的下载来源和构建信息,不参与数据处理) |
| 47 | +``` |
| 48 | + |
| 49 | +### 核心原则 |
| 50 | + |
| 51 | +- 质谱库存谱图数据(peaks),化合物库存化合物属性(标签/结构/交叉引用) |
| 52 | +- 两库通过 InChIKey 关联——Level 2 匹配命中后查化合物库拿标签,Level 3 直接在化合物库搜 |
| 53 | +- confidence/instrument/polarity 是谱图属性(同一化合物可有不同仪器的谱图),留在质谱库 |
| 54 | +- chemical_class/application/sample/reg_lists 是化合物属性,放在化合物库 |
| 55 | +- Level 1(用户自建标准品库)和 Level 4(算法推算分子式)不需要额外库 |
| 56 | + |
| 57 | +### 标签维度分配 |
| 58 | + |
| 59 | +| 维度 | 化合物级 | 谱图级 | 说明 | |
| 60 | +|------|---------|--------|------| |
| 61 | +| chemical_class | ✅ | — | 化学结构类别 | |
| 62 | +| application | ✅ | — | 应用场景 | |
| 63 | +| sample | ✅ | — | 样本基质/来源 | |
| 64 | +| reg_lists | ✅ | — | 监管清单成员 | |
| 65 | +| confidence | — | ✅ | 谱图可信度 | |
| 66 | +| instrument | — | ✅ | 采集仪器 | |
| 67 | +| polarity | — | ✅ | 离子模式 | |
| 68 | + |
| 69 | +--- |
| 70 | + |
| 71 | +## 2. compound_metadata.csv 字段定义 |
| 72 | + |
| 73 | +由 `level3_compounds.csv` 升级而来: |
| 74 | + |
| 75 | +### 基础属性 |
| 76 | + |
| 77 | +| 字段 | 类型 | 说明 | |
| 78 | +|------|------|------| |
| 79 | +| `inchikey` | string | 主键,27 字符 | |
| 80 | +| `name` | string | 化合物名称(缺失时填 InChIKey 前 14 位) | |
| 81 | +| `formula` | string | 分子式 | |
| 82 | +| `exact_mass` | float | 单同位素精确质量(缺失时从 SMILES 用 RDKit 计算) | |
| 83 | +| `smiles` | string | SMILES 结构式(98.9% 覆盖率) | |
| 84 | + |
| 85 | +### 化合物级标签(4 维) |
| 86 | + |
| 87 | +| 字段 | 类型 | 说明 | 示例值 | |
| 88 | +|------|------|------|--------| |
| 89 | +| `chemical_class` | string | 化学结构类别(对齐 NPClassifier) | metabolite, lipid, pfas, pesticide, alkaloid, terpenoid, amino_acid_peptide, carbohydrate, steroid, glycan, organophosphate, organohalogen, unknown | |
| 90 | +| `application` | string | 应用/监管场景 | pharmaceutical, environmental_monitoring, food_safety, forensic, toxicology, agrochemical, general | |
| 91 | +| `sample` | string | 样本基质/生物来源 | human, plant, microbial, marine, water, soil, air, blood, urine, food, synthetic, unknown | |
| 92 | +| `reg_lists` | string | 监管清单成员(多值分号分隔) | eu_watch_list; stockholm_pops; epa_pfas_master; epa_ccl5; cal_prop65 | |
| 93 | + |
| 94 | +### 交叉引用 |
| 95 | + |
| 96 | +| 字段 | 类型 | 说明 | |
| 97 | +|------|------|------| |
| 98 | +| `kegg_id` | string | KEGG Compound ID | |
| 99 | +| `hmdb_id` | string | HMDB ID | |
| 100 | +| `chebi_id` | string | ChEBI ID | |
| 101 | +| `lipidmaps_id` | string | LipidMaps ID | |
| 102 | +| `cas_number` | string | CAS 登记号 | |
| 103 | + |
| 104 | +### 来源追溯 |
| 105 | + |
| 106 | +| 字段 | 类型 | 说明 | |
| 107 | +|------|------|------| |
| 108 | +| `sources` | string | 数据库来源(HMDB;COCONUT;MassBank 等) | |
| 109 | + |
| 110 | +### 标签规则 |
| 111 | + |
| 112 | +- 允许空值——不是每个化合物都有所有标签 |
| 113 | +- 允许多值——`application=pharmaceutical;environmental_monitoring` |
| 114 | +- 不填默认值——空值表示"未知" |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## 3. 标签填充策略 |
| 119 | + |
| 120 | +### Phase 1(立即,零成本) |
| 121 | + |
| 122 | +| 标签 | 方法 | 来源 | |
| 123 | +|------|------|------| |
| 124 | +| `application` | 从 sources 字段规则推导 | NORMAN→environmental_monitoring, T3DB→toxicology, FooDB→food_safety, ChEBI→pharmaceutical 等 | |
| 125 | +| `chemical_class` | 从 sources 推导基础分类 | HMDB→metabolite, LipidMaps→lipid, COCONUT→natural_product, TSCA→industrial_chemical | |
| 126 | + |
| 127 | +### Phase 2(1-2 天) |
| 128 | + |
| 129 | +| 标签 | 方法 | 来源 | |
| 130 | +|------|------|------| |
| 131 | +| `reg_lists` | 下载 NORMAN SusDat S0(Zenodo, 124MB, CC BY 4.0),用 InChIKey 匹配 130+ 个 S 标签列表 | NORMAN SusDat | |
| 132 | +| `chemical_class` 细化 | 从 SusDat 的列表分类推导 PFAS/pesticide 等细分类别 | NORMAN SusDat | |
| 133 | +| `sample` | HMDB biofluid_locations 回填 human 子类(blood/urine/csf) | HMDB XML | |
| 134 | + |
| 135 | +### Phase 3(3-5 天) |
| 136 | + |
| 137 | +| 标签 | 方法 | 来源 | |
| 138 | +|------|------|------| |
| 139 | +| `chemical_class` 精确 | ClassyFire/NPClassifier API 从 SMILES 批量计算 | ClassyFire API(~90% 覆盖率) | |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## 4. 数据处理流程变更 |
| 144 | + |
| 145 | +### 用户搜索流程 |
| 146 | + |
| 147 | +``` |
| 148 | +用户选标签: chemical_class=pfas, sample=water |
| 149 | +
|
| 150 | +Step 1: compound_metadata.csv 过滤 |
| 151 | + → 筛出符合标签的 InChIKey 集合 |
| 152 | +
|
| 153 | +Step 2: Level 2 匹配(MS2) |
| 154 | + → annot-worker 只对 InChIKey 集合内的谱图做余弦匹配 |
| 155 | + → 无 InChIKey 的谱图默认包含(兜底策略) |
| 156 | + → 命中后从 compound_metadata 拿完整标签写入结果 |
| 157 | +
|
| 158 | +Step 3: Level 2 未命中 → Level 3 匹配(MS1) |
| 159 | + → 只在 InChIKey 集合内的化合物做精确质量匹配 |
| 160 | +
|
| 161 | +Step 4: Level 3 未命中 → Level 4(SIRIUS 分子式推算) |
| 162 | +
|
| 163 | +用户不选标签 → 不过滤,搜全库 |
| 164 | +``` |
| 165 | + |
| 166 | +### 代码变更 |
| 167 | + |
| 168 | +| 文件 | 变更 | |
| 169 | +|------|------| |
| 170 | +| `annot-worker/matchms_engine.py` | 加 `inchikey_filter` 可选参数 | |
| 171 | +| `xcms-worker/R/annotation_ms1.R` | 加 InChIKey 白名单过滤 | |
| 172 | +| 后端 `AnnotationParams` | `tag_filter` 字段对接新标签维度 | |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## 5. 质谱库 InChIKey 补全 |
| 177 | + |
| 178 | +### 当前缺口 |
| 179 | + |
| 180 | +55,636 条谱图(8.3%)无 InChIKey。 |
| 181 | + |
| 182 | +### 补全方案 |
| 183 | + |
| 184 | +| 步骤 | 方法 | 数量 | 预估成功率 | |
| 185 | +|------|------|------|-----------| |
| 186 | +| Step 1 | SMILES → InChIKey(RDKit 本地计算) | 19,667 | ~99% | |
| 187 | +| Step 2 | InChI → InChIKey(RDKit 本地计算) | 1,835 | ~100% | |
| 188 | +| Step 3 | Name → InChIKey(PubChem API 查询) | 33,953 | ~60-80% | |
| 189 | + |
| 190 | +补全后写回 MSP 文件的 `InChIKey:` 字段。 |
| 191 | + |
| 192 | +### 兜底策略 |
| 193 | + |
| 194 | +补不上 InChIKey 的谱图: |
| 195 | +- 用户选标签过滤时,**默认包含**(宁可多搜不漏掉) |
| 196 | +- 匹配结果标注 `tag_verified: false` |
| 197 | +- 用户可在高级设置选择"严格模式"排除无 InChIKey 谱图 |
| 198 | + |
| 199 | +### 新增脚本 |
| 200 | + |
| 201 | +`scripts/backfill_inchikey_spectra.py` — 三步补全 + 报告未补上的条数 |
| 202 | + |
| 203 | +--- |
| 204 | + |
| 205 | +## 6. 文件变更清单与向后兼容 |
| 206 | + |
| 207 | +### 文件变更 |
| 208 | + |
| 209 | +| 变更 | 说明 | |
| 210 | +|------|------| |
| 211 | +| `level3_compounds.csv` → `compound_metadata.csv` | 改名 + 加 4 列标签字段 | |
| 212 | +| `registry.csv` | 不变,继续作为来源管理清单 | |
| 213 | +| `deduplicated/*.msp` | InChIKey 补全后原地更新 | |
| 214 | +| `DATABASE_MANUAL.md` | 更新:双库架构、标签维度、升级原因和过程 | |
| 215 | +| `scripts/rebuild_level3.py` → `scripts/rebuild_compound_metadata.py` | 改名,输出 compound_metadata.csv | |
| 216 | +| `scripts/fill_tags.py` | 新建,标签填充逻辑(Phase 1/2/3) | |
| 217 | +| `scripts/backfill_inchikey_spectra.py` | 新建,质谱库 InChIKey 补全 | |
| 218 | + |
| 219 | +### 向后兼容 |
| 220 | + |
| 221 | +- 软链接:`ln -s compound_metadata.csv level3_compounds/combined/level3_compounds.csv` |
| 222 | +- annot-worker 找不到 compound_metadata.csv 时自动回退到 level3_compounds.csv |
| 223 | +- 新增标签列在旧代码中被 CSV 读取自动忽略 |
| 224 | + |
| 225 | +### 数据清洗(同步执行) |
| 226 | + |
| 227 | +| 操作 | 数量 | |
| 228 | +|------|------| |
| 229 | +| RDKit 从 SMILES 计算缺失 exact_mass | 28,210 条 | |
| 230 | +| 空名字填 InChIKey 前 14 位 | 357,728 条 | |
| 231 | +| 删除无 mass + 无 SMILES + 无 name | 585 条 | |
| 232 | + |
| 233 | +--- |
| 234 | + |
| 235 | +## 7. 设计决策记录 |
| 236 | + |
| 237 | +| 决策 | 理由 | |
| 238 | +|------|------| |
| 239 | +| origin 改名为 sample | 统一覆盖生物来源(human/plant)和环境介质(water/soil),避免两套维度 | |
| 240 | +| reg_lists 不合并到 source | source 是"数据来自哪个数据库",reg_lists 是"在哪些监管清单上",不同问题 | |
| 241 | +| 标签允许空值不填默认值 | 不准确的标签比空值更有害 | |
| 242 | +| 无 InChIKey 谱图默认包含搜索 | 宁可多搜不漏掉,排除需要用户主动选择严格模式 | |
| 243 | +| compound_metadata 而非 compound_database | 强调这是属性表不是独立数据库,避免与"Level 3 数据库"概念混淆 | |
| 244 | +| confidence/instrument/polarity 留在谱图级 | 同一化合物可有不同仪器/可信度的谱图,这三维是谱图属性不是化合物属性 | |
0 commit comments