跳到主要内容

MeiliSearch 搜索

CmsKit 以 MeiliSearch 作为全文检索引擎,为文章沸点提供检索、搜索建议、热搜、历史与高亮。它处在基础设施层,被 Content / Discovery 复用,本身不直接对外暴露业务接口。

为什么引入 MeiliSearch

社区内容的检索需要满足:全文相关性排序、关键词高亮、前缀/模糊建议、热搜榜。关系库的全文检索在中文分词与相关性排序上代价高,因此 CmsKit 把检索职责整体交给 MeiliSearch,业务库只保留「内容本体」。检索结果经 ISearchSuggestionService 包装成建议/热搜/历史/高亮等体验能力(见 发现)。

索引与内容的关系

文章索引按 ArticleCategory 拆分为多个索引(索引名 = articles + _ + 分类名);沸点使用单一索引 shortmsgs

索引 UID对应内容说明
articles_Normal普通文章(ArticleCategory.Normal标题、正文、标签等可检索
articles_AiNewsAI 资讯(ArticleCategory.AiNews同上
shortmsgs沸点正文、话题、圈子相关字段可检索

同步机制:以「轮询增量」为主,发布瞬间直写为辅

内容写入索引有两条路径(均来自 CmsKitJobService,而非请求链路里的领域事件):

  1. 增量同步 IncrementalSyncMeiliSearchAsync:每轮扫描 UpdateTime 落在最近 5 分钟窗口、且「PrivacyType == Public + AuditStatus == Approved + !IsDeleted」的内容,逐条 IndexOrUpdate*;软删除的内容则从索引移除。
  2. 定时发布直写ScheduledPublishAsync 在到点发布文章时,直接 IndexOrUpdateArticleAsync 并发送系统通知——这条路径不走 5 分钟轮询,故定时发布的文章无检索延迟。

选择轮询而非事件驱动是刻意权衡:主写入链路不被搜索引擎拖慢,写入吞吐更稳;代价是新内容最多约 5 分钟才可被检索到(热点发布场景由路径 2 补偿)。后台还提供 InitAllArticlesAsync / InitAllShortMsgsAsync 做全量索引重建(通常由运维/初始化任务触发)。

核心服务

  • IArticleMeiliSearchServiceIndexOrUpdateArticleAsync / DeleteArticleIndexAsync / BulkSyncArticlesAsync / GetQueryArticleListAsync(列表式检索)/ SearchArticlesAsync(关键词检索)。
  • IShortMsgMeiliSearchServiceIndexOrUpdateShortMsgAsync / DeleteShortMsgIndexAsync / BulkSyncShortMsgsAsync / GetQueryShortMsgListAsync / SearchShortMsgsAsync / InitAllShortMsgsAsync
  • ISearchSuggestionService:搜索建议、热搜、历史、记录。
  • IMeiliSearchConfigService:索引/配置相关管理(如 InitializeIndexSettingsAsync)。
  • 底层 MeilisearchClientCmsKitModuleStartup 中注册,地址来自运行时设置。

配置(业务含义)

MeiliSearch 的地址与密钥不是 appsettings 顶层 MeiliSearch,而是由 ICmsKitRuntimeSettingProvider 从系统设置(数据库 Setting 表)读取:

系统设置键名默认值业务含义
MeiliSearch.Host空(回落 http://127.0.0.1:7700MeiliSearch 地址
MeiliSearch.ApiKeyMaster / Search API Key

源码中没有独立的 Enable 开关;只要 MeiliSearch.Host 可达,检索即可用。地址为空时客户端回落到本地默认地址。生产环境建议用 Search-only Key 暴露给前端直连,通过 Identity 系统设置接口写入。

开发示例

// 关键词检索文章(按分类),注入 IArticleMeiliSearchService
var docs = await _articleMeiliSearchService.SearchArticlesAsync("cmskit", page: 1, pageSize: 20,
category: ArticleCategory.Normal);

// 检索沸点,注入 IShortMsgMeiliSearchService
var sms = await _shortMsgMeiliSearchService.SearchShortMsgsAsync("周末", page: 1, pageSize: 20);

// 后台全量重建索引
await _shortMsgMeiliSearchService.InitAllShortMsgsAsync();

部署建议

  • 用 Docker 启动 MeiliSearch 并配置 Master Key;生产环境为前端直连再创建 Search-only Key。
  • 内容发布/更新由增量作业自动维护索引;如需全量重建,调用 InitAll*Async 或批量 BulkSync*Async(通常由运维/后台任务触发)。
  • 监控索引大小与查询耗时,定期用 MeiliSearch 快照备份。

相关文档