# 搜索功能
**本文引用的文件**
- [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)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向“搜索功能”的技术实现与运维优化,覆盖以下主题:
- 全文搜索实现与关键词匹配策略
- 搜索结果排序与相关性评分(当前实现为基于字段包含与时间倒序)
- 搜索索引构建、搜索引擎集成现状与扩展建议
- 缓存策略与性能优化
- 搜索历史记录、热门搜索词统计与搜索建议生成
- 多维度过滤、地理位置筛选、时间范围限制的扩展路径
- 搜索 API 接口规范、参数与返回格式
- 性能优化、查询语句优化、索引维护策略
- 个性化推荐、A/B 测试与用户体验优化建议
- 安全防护、恶意查询过滤与搜索统计分析
## 项目结构
搜索功能由前端页面、后端控制器与服务层、数据库模型以及缓存与安全中间件共同组成。整体采用前后端分离架构,前端通过 HTTP 接口调用后端搜索能力。
```mermaid
graph TB
FE["前端页面
search/index.vue"] --> API["后端接口
search.controller.ts"]
API --> SVC["搜索服务
search.service.ts"]
SVC --> PRISMA["数据库模型
schema.prisma"]
API --> CACHE["缓存中间件
cache.ts"]
API --> SEC["安全中间件
security.ts"]
CACHE --> REDIS["Redis 缓存
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 "前端页面
search/index.vue"
participant CTRL as "控制器
search.controller.ts"
participant SVC as "服务层
search.service.ts"
participant DB as "数据库
Prisma"
participant R as "缓存中间件
cache.ts"
participant RS as "Redis
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["加载搜索上下文
历史 + 热门"]
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["构造查询条件
标题/描述包含"]
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)