fix: 第21轮搜索审计修复 — OR模式NOT回退/子组虚条目/日期OR模式等10项
Bug-R21-1 (CRITICAL): OR模式NOT分离过度 — A OR NOT B语义错误,恢复or_(*conditions) Bug-R21-2 (CRITICAL): 双重嵌套括号sub_group_refs虚条目 — 仅当_ungrouped非空时写入 Bug-R21-3 (HIGH): negated_date_ranges被覆盖 — =改为|= Bug-R21-4 (MEDIUM): 日期/PMID/DOI/PMC条件在OR模式始终AND — 合并为or_(*conditions) Bug-R21-5 (MEDIUM): _parse_atom无条件消费任何词符 — 类型验证守卫 Bug-R21-6 (MEDIUM): 模态框双重goToPage(1) — 按钮只关弹窗,搜索由watcher触发 Bug-R21-7 (MEDIUM): page.value失败后不回退 — 捕获异常恢复前一页 Bug-R21-8 (LOW): 空引号""[TI]产生空Term — text为空时跳过 Bug-R21-9 (LOW): 冗余函数内import re — 使用模块级导入
This commit is contained in:
+78
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文档按修复轮次详细记录所有搜索功能合规性修复的背景、根因分析和修改内容。
|
||||
>
|
||||
> **累计**:20 轮,224 项修复,80+ 字段标签注册,1007 项测试覆盖,7 项已知限制
|
||||
> **累计**:21 轮,235 项修复,80+ 字段标签注册,1007+ 项测试覆盖,7 项已知限制
|
||||
> **时间跨度**:2026-07-24 ~ 2026-07-29
|
||||
> **核心文件**:`pubmed_query_parser.py`(~850 行)→ `search_engine.py`(~1360 行)
|
||||
|
||||
@@ -1508,6 +1508,83 @@
|
||||
| L7 | 字段标签 REF/ISBN 未注册 | 低使用频率或数据缺失 | 低 |
|
||||
| L8 | GIN 索引缺失(基因/chemicals 等) | 需 DBA 操作,生产数据量大 | 中(大表性能) |
|
||||
| L9 | `_dispatch_term` 回归不可见 | 需字段级测试。第 15 轮修复了 `__RANGE_*` 组内回退 | 低 |
|
||||
| L10 | `_has_or` 深度盲区 | `_parse_primary` 在父组范围内搜索 OR token,不限制括号深度。`(A AND (B OR C))` 中父组操作符错误为 "or" | 极低(仅在复杂嵌套触发) |
|
||||
|
||||
---
|
||||
|
||||
## 第二十一轮:第 21 轮审计修复(10 项)
|
||||
|
||||
**日期**:2026-07-29
|
||||
**提交**:`53cf1d6..`(第 20 轮后追加)
|
||||
**数量**:10 项(2 CRITICAL + 1 HIGH + 4 MEDIUM + 3 LOW)
|
||||
**触发**:用户第 16 次要求全面检查(第 21 轮,4 并行审计 agent)
|
||||
**测试**:1007+ 全部通过 + 前端 build 通过
|
||||
|
||||
### Bug-R21-1 (CRITICAL): OR 模式 NOT 分离过度 — `A OR NOT B` 语义错误
|
||||
|
||||
- **文件**:`search_engine.py:1265-1278`
|
||||
- **根因**:R20 将 OR 模式的 `or_(*term_conditions)` 改为分离 UnaryExpression NOT 后独立 AND。`cancer OR NOT review` 被编译为 `cancer AND NOT review`(仅检索 cancer 且不是 review 的文献),而非正确的 PubMed 语义 `cancer OR NOT review`(所有 cancer 文献 + 所有非 review 文献)。
|
||||
- **影响**:OR+NOT 组合查询结果严重过窄。违反"搜索功能必须与 PubMed 完全一致"硬性要求。
|
||||
- **修复**:恢复为 `conditions.append(or_(*term_conditions))`。
|
||||
|
||||
### Bug-R21-2 (CRITICAL): 双重嵌套括号 `sub_group_refs` 虚条目 — 搜索词被丢弃
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:791-798`
|
||||
- **根因**:`_parse_primary` 在 `_ungrouped` 为空(所有词已在前一层分好组)时仍写入 `sub_group_refs`,导致 `sub_group_refs` 比 `groups` 多一项。组索引 0 出现在虚条目的子列表中 → 引擎 `_is_child` 为 True → 整个组被 `continue` 跳过。
|
||||
- **触发**:任何双重嵌套括号 `((cancer[MH]))` 或外层括号内全部是已分组内容的表达式。
|
||||
- **修复**:仅当 `_ungrouped` 非空(即真正创建父组)时才写入 `sub_group_refs`。
|
||||
|
||||
### Bug-R21-3 (HIGH): `negated_date_ranges` 被覆盖而非合并
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:461`
|
||||
- **根因**:第 461 行 `=` 直接覆盖集合,`_dispatch_term` 中单日期 NOT 的 `add()` 被丢弃。`NOT "2024-01-01"[DP]` → 引擎误以正日期过滤。
|
||||
- **修复**:`=` 改为 `|=`。
|
||||
|
||||
### Bug-R21-4 (MEDIUM): 日期/PMID/DOI/PMC 条件在 OR 模式下始终 AND
|
||||
|
||||
- **文件**:`search_engine.py:1377-1380`
|
||||
- **根因**:`_pubmed_conditions` 末尾所有日期/ID 条件 `conditions.append()` → `and_(*conditions)` 强制 AND。`cancer OR 2000:2020[DP]` 实际等同 `cancer AND pub_date in 2000-2020`。
|
||||
- **修复**:OR 模式时 `conditions = [or_(*conditions)]`。
|
||||
|
||||
### Bug-R21-5 (MEDIUM): `_parse_atom` 无条件消费任何词符
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:836-839`
|
||||
- **根因**:`self.advance()` 不验证类型。`cancer OR OR lung` → 第二个 OR 被当作 WORD。
|
||||
- **修复**:读取前验证 `self.peek().type` 是原子类型。
|
||||
|
||||
### Bug-R21-6 (MEDIUM): 模态框触发两次 `goToPage(1)`
|
||||
|
||||
- **文件**:`SearchView.vue:961/981/997`
|
||||
- **根因**:按钮 `@click` 同时设置 `showModal = false`(触发 watcher)和直接 `goToPage(1)`。
|
||||
- **修复**:按钮只设置 `showModal = false`,搜索由 watcher 触发。
|
||||
|
||||
### Bug-R21-7 (MEDIUM): `page.value` 失败后不回退
|
||||
|
||||
- **文件**:`usePagination.ts:23-26`
|
||||
- **根因**:`goToPage` 在 `fetchFn` 前设置 `page.value = n`。
|
||||
- **修复**:捕获异常后恢复 `page.value`。
|
||||
|
||||
### Bug-R21-8 (LOW): 空引号 `""[TI]` 产生空 Term
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:843-846`
|
||||
- **根因**:`""` 被 tokeniser 匹配为 QUOTED,`strip('"')` 后为空。
|
||||
- **修复**:`if not text: return []`。
|
||||
|
||||
### Bug-R21-9 (LOW): 冗余函数内 `import re`
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:997`、`search_engine.py:358/372`
|
||||
- **修复**:移除冗余函数级导入,使用模块级 `import re`。
|
||||
|
||||
### 审计结果汇总
|
||||
|
||||
| 审计维度 | 结果 |
|
||||
|---------|------|
|
||||
| R20 回归(OR NOT 分离) | ✅ 已 revert |
|
||||
| R20 回归(sub_group_refs 虚条目) | ✅ _ungrouped 守卫 |
|
||||
| 搜索引擎代码 | ✅ negated_date_ranges、OR 模式日期条件、冗余导入 |
|
||||
| 解析器/分词器 | ✅ _parse_atom 类型验证、空引号守卫 |
|
||||
| 前端集成 | ✅ 双重 goToPage、page 回滚 |
|
||||
| 已知限制更新 | L4 已修复移除、新增 L10 _has_or 深度盲区 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user