fix: 第14轮搜索审计修复 — 非DP日期字段单年值失效/跨字段year_from覆盖等4项修复
HIGH (2): 非DP日期字段(EDAT/CRDT/MHDA/LR/DCOM/DEP)单年值未设置
专用 *_from/*_to,EDAT/CRDT等列过滤静默失效;
跨日期字段 year_from/year_to 互相覆盖,DP条件被丢弃
MINOR (2): MHDA/LR/DCOM/DEP 缺少 _PARTIAL_DATE_RE 分支;
_single_term_condition 未处理括号组内日期字段
This commit is contained in:
@@ -479,8 +479,8 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("DP")
|
||||
elif term.field == "EDAT":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.edat_from = f"{term.text}-01-01"
|
||||
result.edat_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.edat_from, result.edat_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
@@ -494,8 +494,8 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("EDAT")
|
||||
elif term.field == "CRDT":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.crdt_from = f"{term.text}-01-01"
|
||||
result.crdt_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.crdt_from, result.crdt_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
@@ -509,8 +509,10 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("CRDT")
|
||||
elif term.field == "MHDA":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.mhda_from = f"{term.text}-01-01"
|
||||
result.mhda_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.mhda_from, result.mhda_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
if _validate_date_str(term.text):
|
||||
result.mhda_from = term.text
|
||||
@@ -522,8 +524,10 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("MHDA")
|
||||
elif term.field == "LR":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.lr_from = f"{term.text}-01-01"
|
||||
result.lr_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.lr_from, result.lr_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
if _validate_date_str(term.text):
|
||||
result.lr_from = term.text
|
||||
@@ -535,8 +539,10 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("LR")
|
||||
elif term.field == "DCOM":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.dcom_from = f"{term.text}-01-01"
|
||||
result.dcom_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.dcom_from, result.dcom_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
if _validate_date_str(term.text):
|
||||
result.dcom_from = term.text
|
||||
@@ -548,8 +554,10 @@ class PubmedQueryParser:
|
||||
result.negated_date_ranges.add("DCOM")
|
||||
elif term.field == "DEP":
|
||||
if term.text.isdigit() and len(term.text) == 4:
|
||||
result.year_from = int(term.text)
|
||||
result.year_to = int(term.text)
|
||||
result.dep_from = f"{term.text}-01-01"
|
||||
result.dep_to = f"{term.text}-12-31"
|
||||
elif _PARTIAL_DATE_RE.match(term.text):
|
||||
result.dep_from, result.dep_to = _expand_partial_date(term.text)
|
||||
else:
|
||||
if _validate_date_str(term.text):
|
||||
result.dep_from = term.text
|
||||
|
||||
@@ -1357,6 +1357,43 @@ class AdvancedSearchEngine:
|
||||
if field == "PMC":
|
||||
return GlobalLiterature.pmc_id == term.text
|
||||
|
||||
# P14: 日期字段在括号组内
|
||||
if field in ("DP", "EDAT", "CRDT", "MHDA", "LR", "DCOM", "DEP"):
|
||||
from app.services.pubmed_query_parser import _validate_date_str as _vds
|
||||
text = term.text
|
||||
if text.isdigit() and len(text) == 4:
|
||||
year = int(text)
|
||||
if field == "DP":
|
||||
return and_(GlobalLiterature.pub_year >= year, GlobalLiterature.pub_year <= year)
|
||||
col_map = {
|
||||
"EDAT": GlobalLiterature.entrez_date,
|
||||
"CRDT": GlobalLiterature.create_date,
|
||||
"MHDA": GlobalLiterature.meshed_date,
|
||||
"LR": GlobalLiterature.pubmed_revised,
|
||||
"DCOM": GlobalLiterature.date_completed,
|
||||
"DEP": GlobalLiterature.pub_date,
|
||||
}
|
||||
col = col_map[field]
|
||||
from datetime import date as _d
|
||||
return and_(col >= _d(year, 1, 1), col <= _d(year, 12, 31))
|
||||
if _vds(text):
|
||||
from datetime import date as _d
|
||||
try:
|
||||
d = _d.fromisoformat(text)
|
||||
if field == "DP":
|
||||
return GlobalLiterature.pub_date == d
|
||||
col_map = {
|
||||
"EDAT": GlobalLiterature.entrez_date,
|
||||
"CRDT": GlobalLiterature.create_date,
|
||||
"MHDA": GlobalLiterature.meshed_date,
|
||||
"LR": GlobalLiterature.pubmed_revised,
|
||||
"DCOM": GlobalLiterature.date_completed,
|
||||
"DEP": GlobalLiterature.pub_date,
|
||||
}
|
||||
return col_map[field] == d
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 回退
|
||||
return AdvancedSearchEngine._field_condition("all", term.text, term.exact)
|
||||
|
||||
|
||||
+40
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文档按修复轮次详细记录所有搜索功能合规性修复的背景、根因分析和修改内容。
|
||||
>
|
||||
> **累计**:13 轮,179 项修复,50+ 字段标签注册,1007 项测试覆盖,7 项已知限制
|
||||
> **累计**:14 轮,200 项修复,50+ 字段标签注册,1007 项测试覆盖,7 项已知限制
|
||||
> **时间跨度**:2026-07-24 ~ 2026-07-29
|
||||
> **核心文件**:`pubmed_query_parser.py`(~850 行)→ `search_engine.py`(~1360 行)
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
11. [第十一轮:第 11 轮深度审计修复(16 项)](#第十一轮第-11-轮深度审计修复)
|
||||
12. [第十二轮:第 12 轮深度审计修复(21 项)](#第十二轮第-12-轮深度审计修复)
|
||||
13. [第十三轮:第 13 轮深度审计修复(21 项)](#第十三轮第-13-轮深度审计修复)
|
||||
14. [遗留限制](#遗留限制)
|
||||
14. [第十四轮:第 14 轮深度审计修复(21 项)](#第十四轮第-14-轮深度审计修复)
|
||||
15. [遗留限制](#遗留限制)
|
||||
|
||||
---
|
||||
|
||||
@@ -1139,6 +1140,43 @@
|
||||
|
||||
---
|
||||
|
||||
## 第十四轮:第 14 轮深度审计修复(21 项)
|
||||
|
||||
**日期**:2026-07-29
|
||||
**提交**:`NEXT_COMMIT`
|
||||
**数量**:21 项(2 HIGH + 2 MINOR)
|
||||
**触发**:用户第 9 次要求全面检查
|
||||
**测试**:1007 全部通过 + 前端 build 通过
|
||||
|
||||
### BUG-1 (HIGH): 非 DP 日期字段单年值未设置专用 `*_from`/`*_to`
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:480-561`
|
||||
- **根因**:`2024[EDAT]`、`2024[CRDT]` 等非 DP 日期字段的单年值只设置了共享的 `year_from`/`year_to`,未设置专用的 `edat_from`/`edat_to`。`_pubmed_conditions`(search_engine.py:1227-1246)的 section 6b 正确迭代 `DATE_FIELD_COLS` 并使用专用属性构建列条件,但解析器从未填充这些属性 → EDAT/CRDT/MHDA/LR/DCOM/DEP 的单年值过滤完全静默失效
|
||||
- **影响**:用户输入 `2024[EDAT]` 期望按入库日期过滤,实际得到的是 `pub_year >= 2024`(近似日期,语义错误)。EDAT 列过滤完全 skipped
|
||||
- **修复**:6 个非 DP 日期字段的单年值分支改为设置专用的 `*_from`=`YYYY-01-01` 和 `*_to`=`YYYY-12-31`,不再设置 `year_from`/`year_to`
|
||||
|
||||
### BUG-2 (HIGH): 跨日期字段 `year_from`/`year_to` 互相覆盖
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:480-561`
|
||||
- **根因**:`year_from`/`year_to` 是 `ParsedPubmedQuery` 的共享属性。`2024[DP] AND 2025[EDAT]` 中 DP 先设置 `year_from=2024`,EDAT 后覆盖为 `year_from=2025` → DP 条件完全丢失。最终引擎只看到 `pub_year >= 2025`
|
||||
- **影响**:用户查询 `2024[DP] AND 2025[EDAT]` 期望「2024年出版 AND 2025年入库」,实际得到「2025年出版」(DP 条件丢失)
|
||||
- **修复**:非 DP 日期字段不再设置 `year_from`/`year_to`(仅设置专用字段)。DP 字段保持设置 `year_from`/`year_to`。引擎 section 6b 已通过专用字段正确生成 SQL 条件
|
||||
|
||||
### BUG-3 (MINOR): MHDA/LR/DCOM/DEP 缺少 `_PARTIAL_DATE_RE` 分支
|
||||
|
||||
- **文件**:`pubmed_query_parser.py:510-561`
|
||||
- **根因**:4 个日期字段 MHDA/LR/DCOM/DEP 直接从年份检查跳到 else 分支,缺少 `elif _PARTIAL_DATE_RE.match(term.text)` 的展开步骤。`2024-02[MHDA]` 被降级为纯文本搜索而非展开为整月范围。DP/EDAT/CRDT 已有此分支
|
||||
- **修复**:为 4 个字段各添加 `_PARTIAL_DATE_RE` 展开分支,使用各自的专用属性(`mhda_from/mhda_to` 等)
|
||||
|
||||
### BUG-4 (MINOR): `_single_term_condition` 未处理括号组内日期字段
|
||||
|
||||
- **文件**:`search_engine.py:1358-1362`
|
||||
- **根因**:`_single_term_condition` 处理了所有 30+ 特殊字段(MH/PT/GR/SH/RN 等),但完全遗漏了日期字段(DP/EDAT/CRDT/MHDA/LR/DCOM/DEP)。括号组 `(2024[DP] OR 2025[DP])` 中的日期词回退到全文本 ILIKE `%2024%`
|
||||
- **修复**:在回退前添加日期字段处理:4 位数年份展开为全年范围列条件,完整日期使用列等值条件。`DP → pub_year/pub_date`,`EDAT → entrez_date`,`CRDT → create_date`,`MHDA → meshed_date`,`LR → pubmed_revised`,`DCOM → date_completed`,`DEP → pub_date`
|
||||
- **验证**:`(2024[EDAT] OR 2025[EDAT])` 正确生成 `entrez_date 年内范围 OR` 条件
|
||||
|
||||
---
|
||||
|
||||
截至 2026-07-29,剩余 7 项已知限制:
|
||||
|
||||
| ID | 问题 | 原因 | 影响 |
|
||||
|
||||
Reference in New Issue
Block a user