# 搜索功能

<cite>
**本文引用的文件**
- [search.controller.ts](file://server/src/modules/search/search.controller.ts)
- [search.service.ts](file://server/src/modules/search/search.service.ts)
- [cache.ts](file://server/src/middleware/cache.ts)
- [security.ts](file://server/src/middleware/security.ts)
- [redis.service.ts](file://server/src/services/redis.service.ts)
- [schema.prisma](file://server/prisma/schema.prisma)
- [index.vue](file://my-uniapp-vue3/src/pages/search/index.vue)
- [API.md](file://docs/API.md)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向“搜索功能”的技术实现与运维优化，覆盖以下主题：
- 全文搜索实现与关键词匹配策略
- 搜索结果排序与相关性评分（当前实现为基于字段包含与时间倒序）
- 搜索索引构建、搜索引擎集成现状与扩展建议
- 缓存策略与性能优化
- 搜索历史记录、热门搜索词统计与搜索建议生成
- 多维度过滤、地理位置筛选、时间范围限制的扩展路径
- 搜索 API 接口规范、参数与返回格式
- 性能优化、查询语句优化、索引维护策略
- 个性化推荐、A/B 测试与用户体验优化建议
- 安全防护、恶意查询过滤与搜索统计分析

## 项目结构
搜索功能由前端页面、后端控制器与服务层、数据库模型以及缓存与安全中间件共同组成。整体采用前后端分离架构，前端通过 HTTP 接口调用后端搜索能力。

```mermaid
graph TB
FE["前端页面<br/>search/index.vue"] --> API["后端接口<br/>search.controller.ts"]
API --> SVC["搜索服务<br/>search.service.ts"]
SVC --> PRISMA["数据库模型<br/>schema.prisma"]
API --> CACHE["缓存中间件<br/>cache.ts"]
API --> SEC["安全中间件<br/>security.ts"]
CACHE --> REDIS["Redis 缓存<br/>redis.service.ts"]
```

**图表来源**
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)
- [cache.ts:1-98](file://server/src/middleware/cache.ts#L1-L98)
- [security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [index.vue:1-468](file://my-uniapp-vue3/src/pages/search/index.vue#L1-L468)

**章节来源**
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)
- [cache.ts:1-98](file://server/src/middleware/cache.ts#L1-L98)
- [security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)
- [index.vue:1-468](file://my-uniapp-vue3/src/pages/search/index.vue#L1-L468)

## 核心组件
- 前端搜索页面：负责输入、高亮显示、历史与热门展示、调用后端接口。
- 后端控制器：定义搜索、热门、历史等接口，参数校验与错误处理。
- 搜索服务：封装数据库查询逻辑，维护热门词与历史记录。
- 数据库模型：定义搜索历史与热门搜索词表结构及索引。
- 缓存中间件：提供通用缓存能力，可按需对搜索接口进行缓存。
- 安全中间件：提供 XSS 与 SQL 注入防护，敏感数据脱敏。
- Redis 服务：提供连接、读写、批量删除等操作，支撑缓存中间件。

**章节来源**
- [index.vue:166-250](file://my-uniapp-vue3/src/pages/search/index.vue#L166-L250)
- [search.controller.ts:10-167](file://server/src/modules/search/search.controller.ts#L10-L167)
- [search.service.ts:13-140](file://server/src/modules/search/search.service.ts#L13-L140)
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)
- [cache.ts:13-97](file://server/src/middleware/cache.ts#L13-L97)
- [security.ts:7-153](file://server/src/middleware/security.ts#L7-L153)
- [redis.service.ts:43-149](file://server/src/services/redis.service.ts#L43-L149)

## 架构总览
下图展示了从前端到后端、再到数据库与缓存的整体交互流程。

```mermaid
sequenceDiagram
participant U as "用户"
participant FE as "前端页面<br/>search/index.vue"
participant CTRL as "控制器<br/>search.controller.ts"
participant SVC as "服务层<br/>search.service.ts"
participant DB as "数据库<br/>Prisma"
participant R as "缓存中间件<br/>cache.ts"
participant RS as "Redis<br/>redis.service.ts"
U->>FE : 输入关键词并提交
FE->>CTRL : GET /api/search?q=关键词&limit=N
R-->>CTRL : 命中缓存? 否则透传
CTRL->>SVC : searchAudio(query, limit)
SVC->>DB : 查询书籍标题/描述包含关键词
DB-->>SVC : 返回结果集
SVC-->>CTRL : 结果数组
CTRL-->>FE : 统一响应格式
R-->>RS : 写入缓存(可选)
```

**图表来源**
- [index.vue:224-250](file://my-uniapp-vue3/src/pages/search/index.vue#L224-L250)
- [search.controller.ts:10-36](file://server/src/modules/search/search.controller.ts#L10-L36)
- [search.service.ts:13-35](file://server/src/modules/search/search.service.ts#L13-L35)
- [cache.ts:13-47](file://server/src/middleware/cache.ts#L13-L47)
- [redis.service.ts:52-82](file://server/src/services/redis.service.ts#L52-L82)

## 详细组件分析

### 前端搜索页面（search/index.vue）
- 功能要点
  - 搜索栏输入与确认事件绑定
  - 高亮关键词显示
  - 搜索历史与热门推荐展示
  - 调用后端接口：获取历史、热门、执行搜索、保存历史
  - 本地缓存热门词，提升离线体验
- 关键流程
  - 初始化加载历史与热门
  - 用户点击历史或热门词触发搜索
  - 搜索成功后刷新历史与热门，并更新本地缓存

```mermaid
flowchart TD
Start(["进入搜索页"]) --> LoadCtx["加载搜索上下文<br/>历史 + 热门"]
LoadCtx --> Input["输入关键词"]
Input --> Submit{"是否为空?"}
Submit --> |是| Wait["等待输入"]
Submit --> |否| SaveHist["保存搜索历史"]
SaveHist --> CallAPI["调用 /api/search?q=&limit="]
CallAPI --> Render["渲染结果/高亮关键词"]
Render --> Refresh["刷新历史与热门"]
Refresh --> End(["结束"])
```

**图表来源**
- [index.vue:166-250](file://my-uniapp-vue3/src/pages/search/index.vue#L166-L250)

**章节来源**
- [index.vue:1-468](file://my-uniapp-vue3/src/pages/search/index.vue#L1-L468)

### 后端控制器（search.controller.ts）
- 接口定义
  - GET /api/search：全文搜索（关键词、结果数量限制）
  - GET /api/search/hot：热门搜索词
  - GET /api/search/history：用户搜索历史
  - POST /api/search/history：保存搜索历史
  - DELETE /api/search/history：删除单条历史
  - DELETE /api/search/history/all：清空历史
- 参数与返回
  - 统一响应格式：code、message、data
  - 错误处理：捕获异常并返回友好提示

```mermaid
sequenceDiagram
participant FE as "前端"
participant CTRL as "控制器"
participant SVC as "服务层"
FE->>CTRL : GET /api/search?q=...&limit=...
CTRL->>CTRL : 参数校验
CTRL->>SVC : searchAudio(query, limit)
SVC-->>CTRL : 结果数组
CTRL-->>FE : {code,message,data}
```

**图表来源**
- [search.controller.ts:10-36](file://server/src/modules/search/search.controller.ts#L10-L36)

**章节来源**
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)

### 搜索服务（search.service.ts）
- 搜索逻辑
  - 去除多余空白，构造查询条件（标题/描述包含关键词）
  - 按创建时间倒序排序，限制返回数量
- 热门搜索词
  - 查询热门词表，按 sort 与 count 倒序排序
- 历史记录
  - 获取用户历史，去重并按时间倒序
  - 保存历史时先删同用户同关键词旧记录，再插入新记录
  - 控制每用户最多 20 条历史
  - 同步更新热门词计数（存在则自增，否则新建）

```mermaid
flowchart TD
S1["输入: query, limit"] --> Trim["去除空白"]
Trim --> Empty{"是否为空?"}
Empty --> |是| ReturnEmpty["返回空数组"]
Empty --> |否| Build["构造查询条件<br/>标题/描述包含"]
Build --> Order["按创建时间倒序"]
Order --> Take["限制数量"]
Take --> Exec["执行查询"]
Exec --> Out["返回结果"]
```

**图表来源**
- [search.service.ts:13-35](file://server/src/modules/search/search.service.ts#L13-L35)

**章节来源**
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)

### 数据库模型（schema.prisma）
- 搜索相关模型
  - SearchHistory：用户搜索历史
  - HotSearch：热门搜索词（keyword、count、sort、时间索引）
- 索引设计
  - SearchHistory：复合索引（userId, createdAt）、userId 单列索引
  - HotSearch：sort、count 单列索引
- 与业务关联
  - 服务层通过 Prisma 对上述模型进行 CRUD

```mermaid
erDiagram
USER {
int id PK
string phone
string openid
}
BOOK {
int id PK
string title
text description
datetime createdAt
}
SEARCH_HISTORY {
int id PK
int userId
string keyword
datetime createdAt
}
HOT_SEARCH {
int id PK
string keyword
int count
int sort
datetime createdAt
datetime updatedAt
}
USER ||--o{ SEARCH_HISTORY : "拥有"
BOOK ||--o{ SEARCH_HISTORY : "被搜索"
```

**图表来源**
- [schema.prisma:130-159](file://server/prisma/schema.prisma#L130-L159)
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)

**章节来源**
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)

### 缓存中间件（cache.ts）与 Redis 服务（redis.service.ts）
- 缓存中间件
  - 可配置 TTL、键前缀、自定义键生成器
  - 命中则直接返回缓存；未命中执行请求并将成功响应写入缓存
  - Redis 不可用时自动降级跳过缓存
- Redis 服务
  - 提供 get/set/getJSON/setJSON/del/delPattern 等常用操作
  - 连接状态管理与错误日志

```mermaid
classDiagram
class CacheMiddleware {
+createCache(options)
+clearCache(keyPrefix)
}
class RedisService {
+isAvailable() bool
+get(key) string
+set(key,value,ttl) bool
+getJSON(key) any
+setJSON(key,obj,ttl) bool
+del(key) bool
+delPattern(pattern) bool
}
CacheMiddleware --> RedisService : "使用"
```

**图表来源**
- [cache.ts:13-97](file://server/src/middleware/cache.ts#L13-L97)
- [redis.service.ts:43-149](file://server/src/services/redis.service.ts#L43-L149)

**章节来源**
- [cache.ts:1-98](file://server/src/middleware/cache.ts#L1-L98)
- [redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)

### 安全中间件（security.ts）
- XSS 防护：递归清理请求体与查询参数中的危险字符
- SQL 注入防护：检测常见注入模式并拒绝非法请求
- 敏感数据脱敏：对响应中的敏感字段进行掩码处理

```mermaid
flowchart TD
In["接收请求"] --> XSS["XSS 过滤"]
XSS --> SQL["SQL 注入检测"]
SQL --> OK{"合法?"}
OK --> |否| Block["返回 400"]
OK --> |是| Next["继续后续处理"]
```

**图表来源**
- [security.ts:7-102](file://server/src/middleware/security.ts#L7-L102)

**章节来源**
- [security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)

## 依赖关系分析
- 前端依赖后端接口，后端依赖服务层，服务层依赖 Prisma 模型
- 控制器与服务层之间为清晰的职责边界
- 缓存中间件与安全中间件作为横切关注点，可按需组合使用
- Redis 服务为缓存中间件提供基础设施

```mermaid
graph LR
FE["前端"] --> CTRL["控制器"]
CTRL --> SVC["服务层"]
SVC --> PRISMA["Prisma 模型"]
CTRL --> CACHE["缓存中间件"]
CTRL --> SEC["安全中间件"]
CACHE --> REDIS["Redis 服务"]
```

**图表来源**
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)
- [cache.ts:1-98](file://server/src/middleware/cache.ts#L1-L98)
- [security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)

**章节来源**
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)
- [cache.ts:1-98](file://server/src/middleware/cache.ts#L1-L98)
- [security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [redis.service.ts:1-274](file://server/src/services/redis.service.ts#L1-L274)

## 性能考虑
- 当前实现
  - 搜索使用“包含”匹配，排序按创建时间倒序，未引入全文索引或相关性评分
  - 未对搜索接口启用缓存中间件
- 优化建议
  - 引入全文搜索引擎（如 Elasticsearch/Meilisearch）替代简单包含匹配，支持分词、近似匹配、权重排序
  - 在控制器层对高频搜索接口增加缓存中间件，合理设置 TTL
  - 对热门词与历史接口也启用缓存，降低数据库压力
  - 使用数据库索引优化：在标题/描述字段建立全文索引或联合索引
  - 对搜索服务的查询进行 LIMIT 控制与超时保护
  - 前端对频繁输入进行防抖，减少无效请求
  - 对热门词统计与历史上限控制，避免数据膨胀

[本节为通用性能指导，不直接分析具体文件]

## 故障排查指南
- 搜索无结果
  - 检查关键词是否为空或仅空白字符
  - 确认数据库中是否存在匹配的书籍标题/描述
- 接口报错
  - 查看控制器错误处理返回的 message
  - 检查安全中间件是否拦截了非法字符或注入尝试
- 缓存问题
  - 确认 Redis 连接状态与可用性
  - 检查缓存键前缀与 TTL 设置
- 历史与热门异常
  - 检查服务层保存历史时的去重与上限逻辑
  - 确认热门词计数更新是否成功

**章节来源**
- [search.controller.ts:30-35](file://server/src/modules/search/search.controller.ts#L30-L35)
- [security.ts:61-102](file://server/src/middleware/security.ts#L61-L102)
- [redis.service.ts:43-45](file://server/src/services/redis.service.ts#L43-L45)
- [search.service.ts:72-119](file://server/src/modules/search/search.service.ts#L72-L119)

## 结论
当前搜索功能实现了基础的关键词匹配、历史与热门统计，具备良好的扩展空间。建议下一步引入全文搜索引擎与缓存中间件，完善相关性评分与多维过滤能力，并加强安全与性能优化，以满足更复杂的搜索场景与更高的并发需求。

[本节为总结性内容，不直接分析具体文件]

## 附录

### 搜索 API 接口文档
- 搜索音频
  - 方法与路径：GET /api/search
  - 查询参数：
    - q：关键词（必填）
    - limit：结果数量限制（默认 20）
  - 返回：统一响应格式，data 为结果数组
- 获取热门搜索词
  - 方法与路径：GET /api/search/hot
  - 查询参数：
    - limit：返回数量限制（默认 10）
  - 返回：统一响应格式，data 为热门词数组
- 获取搜索历史
  - 方法与路径：GET /api/search/history
  - 查询参数：
    - userId：用户 ID（必填）
    - limit：返回数量限制（默认 5）
  - 返回：统一响应格式，data 为历史数组
- 保存搜索历史
  - 方法与路径：POST /api/search/history
  - 请求体：
    - userId：用户 ID
    - keyword：关键词（必填）
  - 返回：统一响应格式
- 删除单条搜索历史
  - 方法与路径：DELETE /api/search/history
  - 查询参数：
    - userId：用户 ID
    - keyword：关键词（必填）
  - 返回：统一响应格式
- 清空搜索历史
  - 方法与路径：DELETE /api/search/history/all
  - 查询参数：
    - userId：用户 ID（必填）
  - 返回：统一响应格式

**章节来源**
- [search.controller.ts:10-167](file://server/src/modules/search/search.controller.ts#L10-L167)
- [API.md:488-498](file://docs/API.md#L488-L498)

### 搜索相关性与排序建议
- 当前排序：按创建时间倒序
- 建议排序因子：
  - 文档字段权重（标题、描述）
  - 热度/历史搜索计数
  - 用户偏好与历史行为
  - 时间衰减因子
- 实现方式：
  - 引入全文搜索引擎，支持 TF-IDF、BM25 等评分
  - 在服务层计算加权分数并排序

[本节为概念性建议，不直接分析具体文件]

### 多维度过滤与扩展路径
- 已有字段
  - 标题、描述（包含匹配）
- 建议新增
  - 类别/风格/受众等分类过滤
  - 时长/字数范围限制
  - 发布时间范围
  - 地理位置（若适用）
- 实施步骤
  - 在数据库模型中添加相应字段与索引
  - 在控制器与服务层扩展查询条件
  - 在前端提供过滤控件与持久化

[本节为概念性建议，不直接分析具体文件]

### 缓存策略与安全强化
- 缓存策略
  - 对 /api/search、/api/search/hot、/api/search/history 启用缓存中间件
  - 合理设置 TTL（如热门词 5 分钟，搜索结果 1 分钟）
  - 使用键前缀区分不同接口与用户
- 安全强化
  - 在控制器层启用安全中间件
  - 对用户输入进行严格白名单与长度限制
  - 对高频接口增加限流与黑名单机制

**章节来源**
- [cache.ts:13-97](file://server/src/middleware/cache.ts#L13-L97)
- [security.ts:7-153](file://server/src/middleware/security.ts#L7-L153)