From 4e964c955bd01e19039691de79e4f640c1b05af2 Mon Sep 17 00:00:00 2001 From: "34047007@qq.com" <34047007@qq.com> Date: Tue, 28 Jul 2026 11:41:38 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E7=AC=AC10=E8=BD=AE?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=AE=A1=E8=AE=A1=E4=BF=AE=E5=A4=8D=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=EF=BC=88=E7=BC=93=E5=AD=98=E9=94=AE=E7=A2=B0=E6=92=9E?= =?UTF-8?q?/OR=E8=AF=AD=E4=B9=89/affiliation/=E5=89=8D=E7=AB=AFOR=E5=92=8C?= =?UTF-8?q?=E7=B2=BE=E7=A1=AE=E7=9F=AD=E8=AF=AD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/13-搜索修复全记录.md | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/docs/13-搜索修复全记录.md b/docs/13-搜索修复全记录.md index 351e8a9..7502c5b 100644 --- a/docs/13-搜索修复全记录.md +++ b/docs/13-搜索修复全记录.md @@ -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_length(LOW) + +- **文件**:`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 项已知限制: