跳到主要内容

CmsKit 搜索与运维文档(2026-04)

1. 当前搜索架构(与代码一致)

CmsKit 当前采用 MeiliSearch + Redis 的组合。

  • 检索引擎:MeiliSearch
    • 文章检索服务:FreeKit.CmsKit.Application.Articles.MeiliSearchs.ArticleMeiliSearchService
    • 沸点检索服务:FreeKit.CmsKit.Application.ShortMsgs.MeiliSearchs.ShortMsgMeiliSearchService
    • 索引配置服务:FreeKit.CmsKit.Application.Search.MeiliSearchConfigService
  • 搜索建议与热词:Redis + 内存缓存
    • 服务:FreeKit.CmsKit.Application.Search.SearchSuggestionService
    • 热词 ZSet Key:search:hot
    • 历史 List Key 前缀:search:history:{userId}

2. 对外 API(搜索相关)

2.1 用户端

  • GET /api/cms/search/suggestions

  • GET /api/cms/search/hot

  • GET /api/cms/search/history

  • POST /api/cms/search/history/clear

  • POST /api/cms/search/record

  • POST /api/cms/search/highlight

  • POST /api/cms/search/extract-highlight

  • GET /api/cms/articles/query-by-meili

  • GET /api/cms/articles/search-articles

  • GET /api/cms/short_msg/query-by-meili

2.2 管理端

  • GET /api/cms/admin/articles/init-all
  • GET /api/cms/admin/short-msg/init-all-shortmsgs

3. 运维任务(建议由 Job Host 调度)

任务服务:FreeKit.CmsKit.Application.Jobs.CmsKitJobService

  • InitAllMeiliSearchIndexesAsync
    • 场景:全量重建索引(新环境初始化、索引损坏后恢复)
  • IncrementalSyncMeiliSearchAsync
    • 场景:定时增量同步更新/软删除数据
    • 推荐频率:每 3~5 分钟
  • ScheduledPublishAsync
    • 场景:定时发布文章,同时更新索引
    • 推荐频率:每 1 分钟

4. 推荐配置

4.1 配置项

CmsKitModuleStartup 中已读取 Search 配置段:

  • Search:ArticleSuggestionScore
  • Search:ShortMsgSuggestionScore

建议在生产环境补充:

  • MeiliSearch:Host
  • MeiliSearch:ApiKey
  • Redis 连接配置

4.2 索引健康巡检清单

  • 能否访问 MeiliSearch 健康端点
  • 文章/沸点索引文档总量是否与主库同量级
  • 近 10 分钟增量同步日志是否成功
  • 热词 ZSet 是否持续增长(search:hot)
  • 搜索接口 P95 时延是否低于 200ms

5. 典型故障与处理

5.1 搜索为空

排查顺序:

  1. 确认 MeiliSearch 连接可达
  2. 执行全量初始化接口(文章 + 沸点)
  3. 检查数据是否满足可索引条件(审核通过、公开、未删除)

5.2 热词不更新

排查顺序:

  1. 检查 /api/cms/search/record 是否被调用
  2. 检查 Redis 写权限与 key 过期策略
  3. 清空 hot_searches 内存缓存后复测

5.3 增量不同步

排查顺序:

  1. 检查 Job Host 是否触发 IncrementalSyncMeiliSearchAsync
  2. 检查应用日志中的同步条数
  3. 必要时执行全量初始化兜底

6. 建议监控指标

  • meili_index_docs_total{index=article|shortmsg}
  • cms_search_request_total{type=suggestion|meili_query}
  • cms_search_request_duration_ms
  • cms_search_hot_keyword_total
  • cms_search_sync_success_total / cms_search_sync_fail_total