🏗️ 架构概述
基于我对代码的深入分析,该项目使用RediSearch模块构建了一套完整的全文索引系统。整个索引机制采用分层异步架构,确保索引构建不影响主业务流程的响应性能。
📊 索引结构设计
1. 三套独立索引体系
系统设计了三套独立的RediSearch索引,分别处理不同类型的搜索需求:
Topic索引 (idx:topic)
// 索引键格式:zhichai:search:topic:{id}
{{LATEX:1}}redisPrefix . 'search:topic:',
'SCHEMA',
'title', 'TEXT', 'WEIGHT', '5', // 标题权重最高
'content', 'TEXT', 'WEIGHT', '1', // 内容基础权重
'author', 'TEXT', 'WEIGHT', '1.5', // 作者权重中等
'created_at', 'NUMERIC', 'SORTABLE', // 支持时间排序
'reply_count', 'NUMERIC', 'SORTABLE', // 支持热度排序
'is_hidden', 'TAG', // 隐藏状态过滤
'is_closed', 'TAG' // 关闭状态过滤
);
Reply索引 (idx:reply)
// 索引键格式:zhichai:search:reply:{id}
'SCHEMA',
'content', 'TEXT', 'WEIGHT', '2', // 回复内容权重高
'author', 'TEXT', 'WEIGHT', '1', // 作者权重基础
'topic_title', 'TEXT', 'NOINDEX', // 仅显示,不参与搜索
'topic_id', 'TAG', // 话题关联
'created_at', 'NUMERIC', 'SORTABLE',
'is_hidden', 'TAG'
User索引 (idx:user)
// 索引键格式:zhichai:search:user:{id}
'SCHEMA',
'nickname', 'TEXT', 'WEIGHT', '3', // 昵称权重最高
'username', 'TEXT', 'WEIGHT', '2', // 用户名权重中等
'created_at', 'NUMERIC', 'SORTABLE',
'status', 'TAG' // 用户状态过滤
🔄 索引构建流程
1. 自动索引确保机制
系统采用懒加载策略,在首次搜索时自动确保索引存在:
public function ensureIndexes(): void
{
{{LATEX:2}}indexes as {{LATEX:3}}this->redis->rawCommand('FT.INFO', {{LATEX:4}}e) {
// 索引不存在,自动创建
error_log("[SearchService] 索引 {\(idx} 不存在,开始创建");\)this->createIndex(\(idx);
}
}
}
```
### 2. 实时索引更新机制
每当有新数据创建或更新时,系统会**立即**更新对应的搜索索引:
#### Topic索引更新
```php
public function indexTopic(array\)topic): void
{
\(docKey = "search:topic:" .\)topic['id'];
// 内容长度限制,防止索引过大
\(content =\)topic['content'] ?? '';
if (strlen(\(content) > 10000) {\)content = substr(\(content, 0, 10000);
}\)hash = [
'title' => \(topic['title'] ?? '',
'content' =>\)content,
'author' => \(topic['author_nickname'] ?? '',
'created_at' => (string)(strtotime(\)topic['created_at'] ?? 'now')),
'reply_count' => (string)(\(topic['reply_count'] ?? 0),
'is_hidden' =>\)topic['is_hidden'] ? '1' : '0',
'is_closed' => \(topic['is_closed'] ? '1' : '0',
];
try {
// 直接写入Redis Hash,RediSearch自动监听\)this->redis->hMSet(\(docKey,\)hash);
error_log("[SearchService] 成功索引 Topic {{{LATEX:16}}e) {
// 索引失败不影响主流程,仅记录日志
error_log("[SearchService] 索引 Topic {\(topic['id']} 失败: " .\)e->getMessage());
}
}
3. 异步队列处理
为了不影响主业务性能,索引更新通过异步队列进行处理:
// 在TopicService中的异步创建流程
public function createTopicAsync({{LATEX:18}}title, {{LATEX:19}}creationTime = null)
{
// ... 创建Topic逻辑 ...
try {
// 1. 立即写入Redis(同步)
{{LATEX:20}}topicKey, {{LATEX:21}}this->redis->zAdd({{LATEX:22}}timestamp, {{LATEX:23}}this->asyncWriter->enqueue('INSERT', 'topics', {{LATEX:24}}searchService = new SearchService();
{{LATEX:25}}topicArray);
} catch (\Exception {{LATEX:26}}q, string {{LATEX:27}}page = 1, int {{LATEX:28}}escapedTerm = {{LATEX:29}}clean);
// 使用通配符包装,支持部分匹配
{{LATEX:30}}escapedTerm}*";
// 根据权限过滤隐藏内容
if (!\(includeHidden) {\)topicPattern = "({{{LATEX:32}}allDocs, function({{LATEX:33}}b) {
// 先比较相关性得分(命中次数越多得分越高)
{{LATEX:34}}b['_score'] <=> {{LATEX:35}}scoreDiff !== 0) {
return {{LATEX:36}}timeA = (int)({{LATEX:37}}timeB = (int)({{LATEX:38}}timeB <=> {{LATEX:39}}searchPattern = 'search:*';
do {
{{LATEX:40}}redis->scan({{LATEX:41}}searchPattern, 200);
foreach ({{LATEX:42}}k) {
{{LATEX:43}}k);
{{LATEX:44}}it !== 0);
// Step 2: 删除并重建索引
foreach (['idx:topic', 'idx:reply', 'idx:user'] as {{LATEX:45}}redis->rawCommand('FT.DROPINDEX', {{LATEX:46}}searchService->ensureIndexes();
// Step 3: 扫描并索引所有数据
{{LATEX:47}}pdo->query("SELECT * FROM topics ORDER BY created_at DESC");
foreach ({{LATEX:48}}topicData) {
{{LATEX:49}}topicArray);
}
2. 性能优化
- 批量处理: 每100条记录输出进度
- 错误隔离: 单个文档失败不影响整体重建
- 内存控制: 大内容自动截断防止内存溢出
💾 缓存策略
1. 搜索结果缓存
// 生成缓存键
{{LATEX:50}}clean . {{LATEX:51}}page . {{LATEX:52}}includeHidden ? '1' : '0'));
// 缓存搜索结果(TTL 60秒,平衡实时性与性能)
{{LATEX:53}}cacheKey, 60, json_encode({{LATEX:54}}redis->setOption(Redis::OPT_PREFIX, 'zhichai:');
🛡️ 容错处理
1. 超时保护
try {
// Redis操作依赖连接的默认超时
{{LATEX:55}}docKey, {{LATEX:56}}e) {
// 索引失败不影响主流程,只记录日志
error_log("[SearchService] 索引失败: " . $e->getMessage());
}
2. 降级策略
- 核心功能优先: Topic/Reply创建必须成功
- 辅助功能容错: 搜索索引失败仅记录日志
- 异步重试: 通过异步队列支持重试机制
📈 性能特性
1. 查询性能
- 索引查询: O(log N) 时间复杂度
- 全文搜索: 毫秒级响应时间
- 分页支持: 高效的LIMIT/OFFSET实现
2. 写入性能
- 异步索引: 不阻塞主业务流程
- 批量处理: 减少Redis往返次数
- 内容截断: 防止大文档影响性能
🎯 总结
该Redis全文索引系统体现了以下设计亮点:
- 分层架构: 清晰的职责分离,便于维护和扩展
- 异步处理: 保证主业务性能不受索引构建影响
- 智能搜索: 支持中英文混合、部分匹配、权重排序
- 容错机制: 完善的错误处理和降级策略
- 运维友好: 提供完整的重建和监控工具
这套索引系统不仅满足了当前的全文搜索需求,还为未来的功能扩展预留了充分的灵活性。
登录后可参与表态
讨论回复
加载中...
正在加载回复...
正在加载回复...
推荐
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。
领取 2000万 Tokens
通过邀请链接注册即可获得大礼包,期待和你一起在 BigModel 上畅享卓越模型能力