Files
backend/docs/14-高级搜索独立页面设计.md
T
34047007@qq.com a6cd99a4ca
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
feat: initial commit - oncology literature search platform
OncoLit: a multi-tenant oncology literature search, feed, and
collaboration platform. Built with FastAPI + Vue 3 + PostgreSQL.
Includes PubMed pipeline, drug approvals, AI summaries, and
systematic review tools.
2026-07-27 07:59:18 +08:00

11 KiB
Raw Blame History

高级搜索独立页面设计(PubMed 风格)

文档日期:2026-07-24 状态:已规划,暂不实现(先完成普通搜索 Phase 0 Bug 修复) 设计目标:在 /app/search/advanced 独立路由上实现 PubMed 风格的 Advanced Search


1. 问题

当前系统的"高级搜索"只是 SearchView 上的一个筛选面板(年份范围、期刊等级、标签),与 PubMed 的 Advanced Search/pubmed/advanced/)完全不同。

PubMed Advanced Search 是两个核心功能的组合:

  1. 查询构建器(Query Builder — 行式字段下拉 + AND/OR/NOT 组合
  2. 搜索历史(Search History — #1/#2/#3 编号,可点击组合为 #1 AND #2

2. 目标界面

┌─────────────────────────────────────────────────────────┐
│  [Basic Search]  [Advanced Search]  ← Tab 切换           │
├─────────────────────────────────────────────────────────┤
│ 查询构建器(Query Builder                               │
│ ┌───────┬────────────────────────────────────┬──────┐    │
│ │  字段  │  查询词                          │ ×    │    │
│ ├───────┼────────────────────────────────────┼──────┤    │
│ │ All   │ lung cancer                       │ ×    │    │
│ │ AND ▼ │                                    │      │    │
│ │ MeSH  │ lung neoplasms                    │ ×    │    │
│ └───────┴────────────────────────────────────┴──────┘    │
│ [+ Add row]  [Search]  [Details ▼]                       │
│ ── PubMed 查询字符串 ────────────────────────────────     │
│ (lung cancer[All Fields]) AND (lung neoplasms[MeSH Terms])│
├─────────────────────────────────────────────────────────┤
│ 搜索历史(Search History                                │
│ ┌──────┬─────────────────────────┬───────┬──────────┐    │
│ │  #   │ Query                   │ Hits  │ Time     │    │
│ ├──────┼─────────────────────────┼───────┼──────────┤    │
│ │  #3  │ #1 AND #2               │   42  │ 10:32 AM │    │
│ │  #2  │ lung neoplasms[MH]      │  128  │ 10:31 AM │    │
│ │  #1  │ lung cancer[TI]         │  215  │ 10:30 AM │    │
│ └──────┴─────────────────────────┴───────┴──────────┘    │
│ [Combine selected]  [Clear history]                      │
├─────────────────────────────────────────────────────────┤
│ 搜索结果区域                                             │
│ (复用现有 LiteratureCard + Pagination                   │
└─────────────────────────────────────────────────────────┘

3. 页面布局

┌──────────────┬──────────────────────────────────┐
│  左栏        │  右栏                             │
│  280px       │  flex: 1                         │
│              │                                  │
│  Search      │  Query Builder (上区)             │
│  History     │  + 查询字符串显示                  │
│  Panel       │                                  │
│              │  ───────── 分割线 ────────        │
│              │                                  │
│              │  Search Results (下区)            │
│              │  复用 LiteratureCard              │
│              │  + Pagination                    │
└──────────────┴──────────────────────────────────┘

4. 后端改动

4.1 新建模型 SearchHistory

字段 类型 说明
id UUID PK
user_id FK → users
query_text TEXT 用户输入的原始查询字符串
query_json JSON 结构化查询(各字段解析结果)
result_count INTEGER 结果数
created_at TIMESTAMPTZ 搜索时间

文件backend/app/models/search_history.py(新建) 导出backend/app/models/__init__.py 添加 SearchHistory 迁移alembic revision --autogenerate -m "add_search_history"

4.2 API 端点

挂载在 features router 下(backend/app/api/v1/features.py):

方法 路径 说明
POST /features/search/advanced 已有。搜索结果后自动存入 history
GET /features/search/history 获取用户最近 20 条搜索历史
DELETE /features/search/history/{id} 删除单条历史
GET /features/search/details 查询翻译详情(ATM 展开后的结构)

4.3 搜索自动入 History

修改 advanced_search():搜索成功后自动 INSERT 一条 SearchHistory 记录。

# 伪代码
result = await AdvancedSearchEngine.search(db, ...)
history = SearchHistory(
    user_id=user.id,
    query_text=req.query,
    query_json=parsed_query,  # 解析后的结构化字段
    result_count=result["total"],
)
db.add(history)
await db.commit()

4.4 查询构建器 → 后端适配

前端行式构建器发送的结构:

{
  "query": "(lung[TI]) AND (lung neoplasms[MH])",
  "advanced_builder": {
    "rows": [
      {"field": "TI", "query": "lung", "operator": "AND"},
      {"field": "MH", "query": "lung neoplasms", "operator": null}
    ]
  }
}

AdvancedSearchRequest 新增 advanced_builder 可选字段。

4.5 查询详情端点

@router.get("/search/details")
async def search_details(query: str = Query(...)):
    """返回 ATM 展开后的查询结构(类似 PubMed 'Search details' 面板)"""
    parsed = parse_pubmed_query(query)
    return {
        "parsed": parsed.model_dump(),
        "translated": expanded_query,  # ATM 引擎(Phase 1.7 后)
    }

5. 前端改动

5.1 QueryBuilder.vue

位置frontend/src/components/search/QueryBuilder.vue

功能:行式查询构建器

  • 每行:[NSelect 字段] + [NInput 查询词] + [NSelect AND/OR/NOT] + [删除按钮]
  • 第一行无运算符选择
  • 底部 [+ Add row] 按钮
  • 字段下拉选项(12 个):
标签
All Fields ALL
Title TI
Title/Abstract TIAB
Author AU
MeSH Terms MH
MeSH Major Topic MAJR
Journal TA
Affiliation AD
Language LA
Publication Type PT
Grant Number GR
Chemical NM
  • 自动生成 PubMed 语法字符串:(lung[TI]) AND (lung neoplasms[MH])
  • [Search] → 调用 POST /features/search/advanced
  • [Add to history] → 后端自动存,无需手动

Props: 无 Emits: @search(query: string, field: string, ...params)

5.2 SearchHistoryPanel.vue

位置frontend/src/components/search/SearchHistoryPanel.vue

功能:搜索历史表格

  • 加载时调用 GET /features/search/history
  • 表格列:#、Query、Hits、Time
  • 点击行 → 将 #1 语法插入 Query Box
  • 行操作:删除
  • [Combine] → 选中多条 → 生成 #1 AND #2
  • [Clear history] → 调用批量删除

Props: 无 Emits: @useQuery(query: string)@search(query: string)

5.3 AdvancedSearchView.vue

位置frontend/src/views/app/AdvancedSearchView.vue

布局

  • 左栏 280pxSearchHistoryPanel
  • 右栏:上区 QueryBuilder + 下区搜索结果(LiteratureCard + Pagination
  • 顶部 [Basic Search] / [Advanced Search] Tab 切换

依赖

  • LiteratureCard.vue(现有,复用)
  • Pagination(现有,复用)

5.4 路由更新

文件frontend/src/router/index.ts

{ path: 'search/advanced', name: 'search-advanced',
  component: () => import('../views/app/AdvancedSearchView.vue') }

5.5 侧边栏

在导航增加入口:搜索高级搜索

文件:检查侧边栏组件(Sidebar.vue 或布局文件)

5.6 TypeScript 类型更新

文件frontend/src/types/index.ts

export interface AdvancedBuilderRow {
  field: string
  query: string
  operator: 'AND' | 'OR' | 'NOT' | null
}

export interface SearchHistoryItem {
  id: string
  query_text: string
  result_count: number
  created_at: string
}

// SearchRequestBody 补充
export interface SearchRequestBody {
  // ...已有字段...
  advanced_builder?: { rows: AdvancedBuilderRow[] }
}

6. 依赖关系

依赖 说明
Phase 0(必须完成) 搜索 BugOR 布尔、MH JOIN、recent_subq)不修复则高级搜索结果也不正确
Phase 1.1tree_number MeSH Terms 字段的子树展开依赖
Phase 1.3-1.5(字段标签) QueryBuilder 的 AD/LA/EDAT 字段依赖
Phase 1.7ATM 引擎) 查询详情面板的 "Translated query" 依赖
无依赖 QueryBuilder UI + SearchHistory 后端可立即实现(框架先搭好)

7. 工作量估算

任务 文件 预估
SearchHistory 模型 + 迁移 models/search_history.py + 迁移脚本 + __init__.py 30min
后端 CRUD 端点 features.pyGET/DELETE history 1h
搜索自动入 history features.py advanced_search() 15min
查询详情端点 features.py 30min
QueryBuilder.vue components/search/QueryBuilder.vue 2-3h
SearchHistoryPanel.vue components/search/SearchHistoryPanel.vue 2h
AdvancedSearchView.vue views/app/AdvancedSearchView.vue 2h
路由 + 侧边栏 + 类型 router, Sidebar, types 30min
合计 ~9-10h

8. 优先级排序

  1. 最优先Phase 0 Bug 修复(12 项,代码已改待提交)
  2. 次优先:此高级搜索独立页面(9-10h
  3. 后续Phase 1-3 字段标签补齐、ATM 引擎、排序优化