Files
app-api/.qoder/repowiki/zh/content/基础设施/搜索引擎.md
T
2026-05-27 18:07:55 +08:00

355 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 搜索引擎
<cite>
**本文引用的文件**
- [internal/search/meilisearch.go](file://internal/search/meilisearch.go)
- [internal/config/meilisearch.go](file://internal/config/meilisearch.go)
- [internal/config/config.go](file://internal/config/config.go)
- [cmd/server/main.go](file://cmd/server/main.go)
- [internal/router/router.go](file://internal/router/router.go)
- [internal/handler/model_list.go](file://internal/handler/model_list.go)
- [internal/handler/model.go](file://internal/handler/model.go)
- [internal/repository/model.go](file://internal/repository/model.go)
- [internal/model/model.go](file://internal/model/model.go)
- [internal/database/mysql.go](file://internal/database/mysql.go)
- [internal/cache/redis.go](file://internal/cache/redis.go)
- [internal/response/response.go](file://internal/response/response.go)
- [README.md](file://README.md)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向 Luxsin 应用 API 项目中的搜索引擎集成,系统性介绍 Meilisearch 的配置与初始化、搜索客户端的创建流程、索引管理策略、全文搜索实现原理以及搜索 API 的使用示例。同时提供性能优化建议、高亮显示、自动补全与相关性排序的扩展思路,以及连接问题诊断、索引重建与性能调优的故障排除指南。内容从基础概念到高级应用,兼顾不同层次开发者需求。
## 项目结构
该项目采用分层架构,围绕 Gin HTTP 框架组织模块:
- 配置层:集中加载运行环境、数据库、Meilisearch、Redis 等配置
- 数据访问层:MySQL 数据库连接与模型扫描
- 搜索层:Meilisearch 客户端与搜索请求封装
- 处理层:HTTP 处理器与路由注册
- 缓存层:Redis 客户端(用于查询缓存等)
- 工具层:统一响应体、日志、编码工具
```mermaid
graph TB
subgraph "应用入口"
MAIN["cmd/server/main.go"]
end
subgraph "配置层"
CFG["internal/config/config.go"]
MS_CFG["internal/config/meilisearch.go"]
end
subgraph "数据访问层"
MYSQL["internal/database/mysql.go"]
REPO["internal/repository/model.go"]
MODEL["internal/model/model.go"]
end
subgraph "搜索层"
SEARCH_CLIENT["internal/search/meilisearch.go"]
end
subgraph "处理层"
ROUTER["internal/router/router.go"]
HANDLER_MODEL["internal/handler/model.go"]
HANDLER_MODEL_LIST["internal/handler/model_list.go"]
end
subgraph "缓存层"
REDIS["internal/cache/redis.go"]
end
MAIN --> CFG
CFG --> MS_CFG
MAIN --> MYSQL
MAIN --> SEARCH_CLIENT
MAIN --> REDIS
ROUTER --> HANDLER_MODEL
ROUTER --> HANDLER_MODEL_LIST
HANDLER_MODEL --> REPO
SEARCH_CLIENT --> MS_CFG
```
图表来源
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
- [internal/config/config.go:18-51](file://internal/config/config.go#L18-L51)
- [internal/config/meilisearch.go:14-37](file://internal/config/meilisearch.go#L14-L37)
- [internal/database/mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [internal/search/meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
- [internal/handler/model.go:19-24](file://internal/handler/model.go#L19-L24)
- [internal/handler/model_list.go:19-24](file://internal/handler/model_list.go#L19-L24)
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
- [internal/model/model.go:5-14](file://internal/model/model.go#L5-L14)
- [internal/cache/redis.go:10-16](file://internal/cache/redis.go#L10-L16)
章节来源
- [README.md:5-17](file://README.md#L5-L17)
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
- [internal/config/config.go:18-51](file://internal/config/config.go#L18-L51)
## 核心组件
- 配置加载与验证:集中加载运行环境、数据库、Meilisearch、Redis 配置,并进行必填项校验
- Meilisearch 客户端:封装搜索请求,限定返回字段,支持上下文取消
- 路由与处理器:对外提供 /audio/modelList 搜索接口,支持分页数量控制与可选 Base64 响应
- 数据访问层:提供按品牌名或型号名的 SQL 查询能力(当前未直接使用 Meilisearch
- 缓存层:Redis 客户端,可用于查询结果缓存
章节来源
- [internal/config/meilisearch.go:8-12](file://internal/config/meilisearch.go#L8-L12)
- [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50)
- [internal/search/meilisearch.go:13-15](file://internal/search/meilisearch.go#L13-L15)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
- [internal/handler/model_list.go:26-56](file://internal/handler/model_list.go#L26-L56)
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
- [internal/cache/redis.go:10-16](file://internal/cache/redis.go#L10-L16)
## 架构总览
应用启动时加载配置,建立数据库与 Meilisearch 连接,注册路由并启动 HTTP 服务。搜索请求通过 /audio/modelList 路由进入处理器,处理器调用搜索客户端执行全文检索,最终以 JSON 或 Base64 编码形式返回。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Router as "路由"
participant Handler as "ModelListHandler"
participant Search as "Meilisearch Client"
participant Engine as "HTTP 引擎"
Client->>Engine : "GET /audio/modelList?key=...&count=..."
Engine->>Router : "匹配 /audio/modelList"
Router->>Handler : "调用 ModelList()"
Handler->>Handler : "解析查询参数<br/>解析 count 与 Base64 选项"
Handler->>Search : "ModelList(ctx, key, count)"
Search->>Search : "构造 SearchRequest<br/>限制返回字段"
Search-->>Handler : "返回 hits 列表"
Handler-->>Client : "JSON 或 Base64 响应"
```
图表来源
- [internal/router/router.go:32-38](file://internal/router/router.go#L32-L38)
- [internal/handler/model_list.go:26-56](file://internal/handler/model_list.go#L26-L56)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
## 详细组件分析
### 配置加载与验证
- 配置结构包含运行环境、监听地址、端口、数据库、Meilisearch、Redis 等字段
- 加载逻辑按环境选择默认值,支持通过环境变量覆盖
- Meilisearch 配置包含 Host、APIKey、Index,均需校验非空
- 启动日志记录已配置的 Meilisearch 主机与索引
章节来源
- [internal/config/config.go:9-16](file://internal/config/config.go#L9-L16)
- [internal/config/config.go:18-51](file://internal/config/config.go#L18-L51)
- [internal/config/meilisearch.go:8-12](file://internal/config/meilisearch.go#L8-L12)
- [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50)
- [cmd/server/main.go:50-54](file://cmd/server/main.go#L50-L54)
### Meilisearch 客户端
- 客户端封装了 IndexManager,负责全文搜索
- 初始化时传入 Host 与 APIKey,选择指定 Index
- ModelList 方法接收 key 与 count,限制返回字段,解码为 map 并返回
- 错误处理统一包装,便于上层捕获
```mermaid
classDiagram
class Client {
-index : "IndexManager"
+NewClient(cfg) : "Client"
+ModelList(ctx, key, count) : "[]map[string]any, error"
}
class MeilisearchConfig {
+Host : "string"
+APIKey : "string"
+Index : "string"
+validate() : "error"
}
Client --> MeilisearchConfig : "依赖"
```
图表来源
- [internal/search/meilisearch.go:13-20](file://internal/search/meilisearch.go#L13-L20)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
- [internal/config/meilisearch.go:8-12](file://internal/config/meilisearch.go#L8-L12)
- [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50)
章节来源
- [internal/search/meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
### 路由与处理器
- 路由在 /audio 下注册 /modelList 接口
- ModelListHandler 解析查询参数 key、count,并支持 Base64 响应
- 调用搜索客户端执行搜索,错误时返回统一错误响应
```mermaid
sequenceDiagram
participant C as "客户端"
participant R as "路由"
participant H as "ModelListHandler"
participant S as "Meilisearch Client"
C->>R : "GET /audio/modelList?key=...&count=..."
R->>H : "ModelList()"
H->>H : "解析 key/count/base64"
H->>S : "ModelList(ctx, key, count)"
S-->>H : "hits"
H-->>C : "JSON 或 Base64"
```
图表来源
- [internal/router/router.go:32-38](file://internal/router/router.go#L32-L38)
- [internal/handler/model_list.go:26-56](file://internal/handler/model_list.go#L26-L56)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
章节来源
- [internal/router/router.go:32-38](file://internal/router/router.go#L32-L38)
- [internal/handler/model_list.go:26-56](file://internal/handler/model_list.go#L26-L56)
### 数据访问层(SQL 查询)
- ModelRepository 支持按品牌名精确匹配与按型号名模糊匹配
- 默认不使用 Meilisearch,直接走数据库查询
- 可作为搜索降级路径或补充场景
```mermaid
flowchart TD
Start(["进入 List"]) --> Trim["去除前后空格"]
Trim --> Switch{"条件分支"}
Switch --> |brandName 非空| BrandQuery["按品牌名精确查询<br/>按名称升序"]
Switch --> |modelName 非空| LikeQuery["按型号名模糊查询<br/>按名称升序"]
Switch --> |否则| Empty["返回空数组"]
BrandQuery --> Exec["执行查询"]
LikeQuery --> Exec
Exec --> Scan["逐行扫描并组装模型"]
Scan --> End(["返回结果"])
Empty --> End
```
图表来源
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
- [internal/model/model.go:5-14](file://internal/model/model.go#L5-L14)
章节来源
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
- [internal/model/model.go:5-14](file://internal/model/model.go#L5-L14)
### 数据库连接与模型扫描
- 使用 go-sql-driver/mysql 建立连接,设置字符集、时区与连接池参数
- PingContext 超时检测连接可用性
- 扫描函数将 NullString 转换为指针类型,避免空值污染
章节来源
- [internal/database/mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [internal/repository/model.go:63-86](file://internal/repository/model.go#L63-L86)
### 缓存层(Redis
- 提供 NewClient 工厂方法,按配置创建 Redis 客户端
- 可用于搜索结果缓存、热门关键词缓存等
章节来源
- [internal/cache/redis.go:10-16](file://internal/cache/redis.go#L10-L16)
## 依赖关系分析
- 入口 main 依赖配置加载、数据库、Meilisearch、Redis 与路由
- 路由依赖处理器,处理器依赖搜索客户端与数据库
- 搜索客户端依赖配置模块与 Meilisearch SDK
- 数据库层依赖 MySQL 驱动与配置
```mermaid
graph LR
MAIN["cmd/server/main.go"] --> CFG["internal/config/config.go"]
MAIN --> MYSQL["internal/database/mysql.go"]
MAIN --> SEARCH["internal/search/meilisearch.go"]
MAIN --> REDIS["internal/cache/redis.go"]
ROUTER["internal/router/router.go"] --> HANDLER1["internal/handler/model.go"]
ROUTER --> HANDLER2["internal/handler/model_list.go"]
HANDLER2 --> SEARCH
HANDLER1 --> REPO["internal/repository/model.go"]
REPO --> MODEL["internal/model/model.go"]
```
图表来源
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
- [internal/config/config.go:18-51](file://internal/config/config.go#L18-L51)
- [internal/database/mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [internal/search/meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
- [internal/cache/redis.go:10-16](file://internal/cache/redis.go#L10-L16)
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
- [internal/handler/model.go:19-24](file://internal/handler/model.go#L19-L24)
- [internal/handler/model_list.go:19-24](file://internal/handler/model_list.go#L19-L24)
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
- [internal/model/model.go:5-14](file://internal/model/model.go#L5-L14)
## 性能考虑
- 索引预处理
- 在导入数据前,确保字段映射与排序规则已配置,减少运行时开销
- 对高频查询字段(如品牌名、型号名)建立合适字段权重
- 查询缓存
- 使用 Redis 缓存热点搜索结果,设置合理过期时间
- 对于稳定不变的数据(如品牌列表),可缓存静态结果
- 分页策略
- 控制 count 参数上限,避免一次性返回过多数据
- 结合游标分页或基于主键的分页,提升大结果集性能
- 连接池与超时
- 数据库连接池参数已设置,搜索客户端使用短连接或复用连接视场景而定
- 设置合理的读写超时与上下文取消,防止阻塞
- 字段裁剪
- 仅返回必要字段,降低网络传输与序列化成本
- 相关性与排序
- 使用 Meilisearch 的排序与过滤能力,避免后端二次排序
- 日志与监控
- 记录搜索耗时、命中率与错误统计,便于定位性能瓶颈
## 故障排除指南
- 连接问题诊断
- 检查 MEILISEARCH_HOST、MEILISEARCH_API_KEY、MEILISEARCH_INDEX 是否正确设置
- 确认 Meilisearch 服务可达且端口开放
- 查看启动日志中 Meilisearch 配置是否正确加载
- 索引重建
- 如需重建索引,先清空旧索引,再批量导入数据,最后更新字段映射与排序规则
- 导入完成后进行回归测试,确保搜索结果符合预期
- 性能调优
- 逐步增加 count 上限,观察延迟变化,找到平衡点
- 对热点查询启用缓存,减少重复请求
- 优化数据库查询(如品牌/型号过滤)作为降级方案
- 错误处理
- 搜索失败时返回统一错误响应,便于前端提示
- 对 decode 失败、上下文取消等异常进行分类处理
章节来源
- [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50)
- [cmd/server/main.go:50-54](file://cmd/server/main.go#L50-L54)
- [internal/handler/model_list.go:37-42](file://internal/handler/model_list.go#L37-L42)
- [internal/response/response.go:34-36](file://internal/response/response.go#L34-L36)
## 结论
本项目已实现 Meilisearch 的基础集成:配置加载、客户端初始化与搜索接口。当前搜索接口主要返回指定字段的命中结果,未涉及高亮、自动补全与相关性排序的高级特性。建议后续在以下方面增强:
- 高亮显示:利用 Meilisearch 的高亮能力,返回匹配片段
- 自动补全:结合前缀匹配与热门词,提供输入建议
- 相关性排序:配置字段权重与排序规则,提升搜索体验
- 索引策略:按业务维度拆分索引,优化写入与查询性能
- 缓存策略:引入 Redis 缓存,显著降低重复查询延迟
## 附录
### 搜索 API 使用示例
- 设备型号搜索
- 请求:GET /audio/modelList?key=型号关键词&count=100
- 响应:返回命中的设备列表(仅包含指定字段)
- 品牌过滤
- 当前未直接使用 Meilisearch 实现品牌过滤,可通过数据库查询替代
- 请求:GET /audio/getModel?brandName=品牌名
- 结果排序
- 当前未显式设置排序,可结合 Meilisearch 的排序规则实现
- Base64 响应
- 可通过查询参数 base64=true 获取 Base64 编码的 JSON
章节来源
- [internal/handler/model_list.go:26-56](file://internal/handler/model_list.go#L26-L56)
- [internal/handler/model.go:26-50](file://internal/handler/model.go#L26-L50)
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)