docs: 新增第10轮搜索审计修复记录(缓存键碰撞/OR语义/affiliation/前端OR和精确短语)
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s

This commit is contained in:
34047007@qq.com
2026-07-28 11:41:38 +08:00
parent a985d07724
commit 4e964c955b
+58 -3
View File
@@ -2,9 +2,9 @@
> 本文档按修复轮次详细记录所有搜索功能合规性修复的背景、根因分析和修改内容。
>
> **累计**9 轮,115 项修复,50+ 字段标签注册,1007 项测试覆盖,7 项已知限制
> **累计**10 轮,121 项修复,50+ 字段标签注册,1007 项测试覆盖,7 项已知限制
> **时间跨度**2026-07-24 ~ 2026-07-28
> **核心文件**`pubmed_query_parser.py`~730 行)→ `search_engine.py`~1320 行)
> **核心文件**`pubmed_query_parser.py`~730 行)→ `search_engine.py`~1350 行)
---
@@ -19,7 +19,8 @@
7. [第七轮:第 7 轮深度审计修复(20 项)](#第七轮第-7-轮深度审计修复)
8. [第八轮:第 8 轮深度审计修复(12 项)](#第八轮第-8-轮深度审计修复)
9. [第九轮:第 9 轮深度审计修复(5 项)](#第九轮第-9-轮深度审计修复)
10. [遗留限制](#遗留限制)
10. [第十轮:第 10 轮深度审计修复(6 项)](#第十轮第-10-轮深度审计修复)
11. [遗留限制](#遗留限制)
---
@@ -773,6 +774,60 @@
---
## 第十轮:第 10 轮深度审计修复(6 项)
**日期**2026-07-28
**提交**`a985d07`
**数量**6 项
**测试**1007 全部通过 + 前端 build 通过
### P10-1: 缓存键 PubMed/纯文本路径碰撞(MEDIUM
- **文件**`search_engine.py:33-86,88-144`
- **根因**`_search_cache_key` 和 `_facet_cache_key` 只对 query 做 `strip().lower()` 归一化,不区分 PubMed 路径和纯文本路径。相同文本先走 PubMed 路径被缓存,后续纯文本路径命中同样的 key 返回不匹配的结果
- **修复**:在 norm dict 中加入 `"pm": _is_pm(query)` 标志,两路径缓存键自动分离
### P10-2: OR 模式 NOT 语义错误(HIGH
- **文件**`search_engine.py:1151-1153`
- **根因**`boolean_operator == "or"` 路径中,代码提取 `neg_conds` 然后 `and_(pos_conds + neg_conds)`。正确语义应为 `A OR NOT B` 等价于 `A OR (NOT B)`,而非 `(A) AND (NOT B)`
- **修复**OR 模式直接 `or_(*term_conditions)`,不做 NOT 分离
- **验证**:原有 `test_or_mode_mixed_not` 等测试正确通过
### P10-3: Affiliation 始终不在全字段搜索中(MEDIUM)
- **文件**`search_engine.py:1388-1433`
- **根因**`_field_condition("all")` 的 5 条分支(exact/phraseto_tsquery、wildcard ILIKE、"/" 路径、中文路径、tsvector 默认)均未包含 affiliation ILIKE 兜底。虽然 tsvector 默认路径注释写"affiliation 不在 tsvector 中,以 ILIKE 兜底",但代码中并未实现
- **修复**:所有 5 条分支均添加 `jsonb_array_elements(authors)` 的 `->>'affiliation' ILIKE` 子查询
- **影响**:搜索"mayo clinic"或"MD Anderson"等机构名在全字段搜索中生效
### P10-4: 高级搜索无 query max_lengthLOW
- **文件**`features.py:52`
- **修复**`query: str = Field("", max_length=2000)`
- **注意**:延续 P9-5 的修复,Pydantic 层面增加长度限制
### P10-5: 前端缺少 OR 模式切换(MEDIUM)
- **文件**`SearchView.vue:45-46,278-284,547-550`
- **根因**`boolean: 'and'` 硬编码,前端无法发起 OR 搜索
- **修复**
- 搜索栏添加 AND/OR 选择器(NSelect
- `booleanOp` ref 驱动 `body.boolean`
- URL 同步:`route.query.boolean === 'or'` 恢复
- `resetAllFilters` 重置
### P10-6: 前端缺少精确短语模式(LOW)
- **文件**`SearchView.vue:45-46,284,548-550`
- **根因**`exact_phrase` 在 TypeScript 接口中存在但从未从前端发送
- **修复**
- 搜索栏添加"精确短语"复选框
- `body.exact_phrase` 条件发送
- URL 同步/恢复
---
## 遗留限制
截至 2026-07-28,剩余 7 项已知限制: