fix: 第22轮搜索审计修复 — De Morgan语义/部分日期/has_not/custom URL等8项
Bug-R22-1 (MEDIUM): OR模式特殊字段NOT产生错误De Morgan语义 — 17处修正 Bug-R22-2 (MEDIUM): has_not不反映日期范围NOT — 添加_date_range_markers检查 Bug-R22-3 (MEDIUM): YYYY-MM[DP]未引号部分日期无法解析 — 预处理器标准化 Bug-R22-4 (MEDIUM): date_preset=custom URL恢复丢失年份范围 — 读取URL参数 Bug-R22-5 (MEDIUM): 错误状态下分页总数残留 — 搜索开始时重置total Bug-R22-6 (LOW): 搜索错误状态未在开始时清除 — 搜索开始时重置searchError Bug-R22-7 (LOW): DATE token不在未消耗标记恢复处理器中 — 添加DATE类型 Bug-R22-8 (LOW): 外部NOT组内is_not被忽略 — 保留t.is_not
This commit is contained in:
+69
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文档按修复轮次详细记录所有搜索功能合规性修复的背景、根因分析和修改内容。
|
||||
>
|
||||
> **累计**:21 轮,235 项修复,80+ 字段标签注册,1007+ 项测试覆盖,7 项已知限制
|
||||
> **累计**:22 轮,248 项修复,80+ 字段标签注册,1007+ 项测试覆盖,7 项已知限制
|
||||
> **时间跨度**:2026-07-24 ~ 2026-07-29
|
||||
> **核心文件**:`pubmed_query_parser.py`(~850 行)→ `search_engine.py`(~1360 行)
|
||||
|
||||
@@ -1588,6 +1588,74 @@
|
||||
|
||||
---
|
||||
|
||||
## 第二十二轮:第 22 轮审计修复(8 项)
|
||||
|
||||
**日期**:2026-07-29
|
||||
**提交**:`c68aa06..`(第 21 轮后追加)
|
||||
**数量**:8 项(5 MEDIUM + 3 LOW)
|
||||
**触发**:用户第 17 次要求全面检查(第 22 轮,4 并行审计 agent)
|
||||
**测试**:1007+ 全部通过 + 前端 build 通过
|
||||
|
||||
### Bug-R22-1 (MEDIUM): OR 模式下特殊字段 NOT 产生错误 De Morgan 语义
|
||||
|
||||
- **文件**:`search_engine.py:944-1167`
|
||||
- **根因**:`term_conditions.append(not_(or_(*neg_conds)))` 在 OR 模式下产生 `NOT(A OR B)` = `NOT A AND NOT B`。正确应为 `or_(not_(A), not_(B))` = `NOT A OR NOT B`。
|
||||
- **影响**:`NOT "Review"[PT] OR NOT "Clinical Trial"[PT]` 搜索结果过窄。
|
||||
- **修复**:将全部 17 处 `term_conditions.append(not_(or_(*neg_conds)))` 改为 `term_conditions.extend(not_(c) for c in neg_conds)`。AND 模式下语义等价,OR/mixed 模式语义修正。
|
||||
|
||||
### Bug-R22-2 (MEDIUM): `has_not` 不反映日期范围 NOT
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:446`
|
||||
- **根因**:`_ungrouped` 过滤掉 `_is_range_end=True` 的标记,`has_not` 不检查 `_date_range_markers`。
|
||||
- **修复**:`has_not` 额外检查 `result._date_range_markers`。
|
||||
|
||||
### Bug-R22-3 (MEDIUM): `YYYY-MM[DP]` 未引号部分日期无法解析
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:1010-1015`
|
||||
- **根因**:`2024-01[DP]` 分词为 `NUMBER(2024) WORD(-01) FIELD([DP])`。`-01` 不匹配 `_PARTIAL_DATE_RE`。
|
||||
- **修复**:预处理器将 `YYYY-MM[date_field]` 标准化为 `YYYY-MM-01[date_field]`。
|
||||
|
||||
### Bug-R22-4 (MEDIUM): `date_preset=custom` URL 恢复丢失年份范围
|
||||
|
||||
- **文件**:`SearchView.vue:393-396`
|
||||
- **根因**:`restoreFromQuery` 在 custom 分支无条件清空 yearFromStr/yearToStr。
|
||||
- **修复**:custom 分支读取 URL 中的 `year_from/year_to`。
|
||||
|
||||
### Bug-R22-5 (MEDIUM): 错误状态下分页总数残留
|
||||
|
||||
- **文件**:`SearchView.vue:274-276`
|
||||
- **根因**:catch 块清空 results 但不清除 total。
|
||||
- **修复**:搜索开始时重置 `total.value = 0`。
|
||||
|
||||
### Bug-R22-6 (LOW): 搜索错误状态未在开始时清除
|
||||
|
||||
- **文件**:`SearchView.vue:274-276`
|
||||
- **根因**:searchError 仅成功后清空。
|
||||
- **修复**:搜索开始时设置 `searchError.value = ''`。
|
||||
|
||||
### Bug-R22-7 (LOW): DATE token 不在未消耗标记恢复处理器中
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:456`
|
||||
- **根因**:未消耗标记处理器仅捕获 WORD/QUOTED/NUMBER。
|
||||
- **修复**:添加 `TokenType.DATE`。
|
||||
|
||||
### Bug-R22-8 (LOW): 外部 NOT 组内 `is_not` 被忽略
|
||||
|
||||
- **文件**:`search_engine.py:1203`
|
||||
- **根因**:`NOT (A OR NOT B)` → `not_(or_(A, B))`,内部 NOT B 被吞掉。
|
||||
- **修复**:组内保留 `t.is_not`。
|
||||
|
||||
### 审计结果汇总
|
||||
|
||||
| 审计维度 | 结果 |
|
||||
|---------|------|
|
||||
| R21 回归 | ✅ 无回归 |
|
||||
| 搜索引擎代码 | ✅ De Morgan 语义 17 处修正、negated 组内 is_not |
|
||||
| 解析器/分词器 | ✅ YYYY-MM 预处理器、has_not 日期范围、DATE 恢复 |
|
||||
| 前端集成 | ✅ custom URL 恢复、total/error 清理 |
|
||||
|
||||
---
|
||||
|
||||
## 附录:测试覆盖统计
|
||||
|
||||
| 测试文件 | 用例数 | 范围 |
|
||||
|
||||
Reference in New Issue
Block a user