全文检索
基于 PostgreSQL tsvector + 应用层 jieba 分词,无需引入 Elasticsearch 即可获得中文全文检索能力。
索引与三级召回
索引:内容创建/更新时,对标题(权重 A)、SEO 关键词 + 摘要(权重 B)、正文 + searchable 扩展字段(权重 C)做 jieba 细粒度分词(cutForSearch),写入 cms_contents.search_vector(GIN 索引)。
查询按三级召回逐级放宽,直到有结果:
- 精确 AND:关键词粗粒度分词 →
plainto_tsquery全 token 命中 →ts_rank_cd相关度排序 + 发布时间倒序 - 前缀 OR 近似:截断词/两侧切词不齐时(如搜「不动产权证书遗」查询侧切出单字「遗」而索引侧只有「遗失」),使用
token:*前缀匹配按 OR 召回,ts_rank_cd保证命中越多越靠前(仅应用层分词配置启用) - 标题 ILIKE 兜底:关键词 ≤ 32 字时整串模糊匹配标题(
pg_trgmGIN 索引加速),兜住词典完全切不准的关键词
tsvector 解析器配置可用环境变量 CMS_TSVECTOR_CONFIG 切换(默认 simple = 应用层 jieba 预分词;设为 zhparser 等 PG 扩展配置时由 PostgreSQL 直接解析原文,跳过应用层分词与第 2 级召回)。
站点级词典与热词治理
- 词典按站点隔离:
extension扩展词加载至该站点独立的 Jieba 实例,stop停用词在索引和查询分词阶段过滤;token 禁止空白与控制字符,加载按词隔离,单个坏词只记录告警而不会使整站词典失效 - 词典任意增删改后整体重建该站点分词实例(
reloadCmsSearchDict),即时生效,无需重启进程 - 可管理热词使用规范化分组/词条表(
cms_hotword_groups/cms_hotwords)保存排序和启停状态,真实热度仍来自 Redis ZSET;带时间范围查询时从搜索日志聚合 - 历史内容在词典变更后通过任务中心执行站点索引重建
检索管理页
「检索管理」(权限 cms:search:manage)三个 Tab:
- 检索测试:输入关键词查看分词结果与高亮命中,一键重建索引(任务中心
cms-search-reindex异步,分批 200 条 + 断点续跑 + 进度) - 自定义词典:jieba 用户词典(词 + 权重)与停用词,支持批量启停/删除;增删改即时热加载
- 搜索热词:前台每次搜索计入 Redis ZSET(
cms:hotwords:{siteId}),支持排行查看与清空;另可维护热词分组与词条(排序、启停),沉淀规范化热词运营数据
死链检测在「SEO 管理 → 死链检测」Tab,见 SEO 与流量。
前台搜索页
/search?q=keyword:永远动态渲染(不静态化、不缓存),关键词截断 64 字符。
搜索结果由服务端生成 URL:站内内容使用栏目 detailPathRule/staticPath 解析后的规范路径,外链内容直接使用已校验的目标地址;标题和摘要高亮先做 HTML 转义再插入 <mark>,模板不应自行拼接链接或把原始 HTML 当作高亮结果。结果摘要取手填 summary,否则取 excerpt 生成列(正文纯文本前 400 字),再按命中词定位片段;结果页查询不读取 body。
公开搜索的内容条件为 published + 未回收 + 未归档 + 未过期,并要求主栏目自身及全部祖先栏目有效启用;栏目停用或其祖先停用后立即从搜索结果消失。搜索结果 URL 统一由服务端按 detailPathRule/staticPath 解析,模板不得自行拼接路径。
搜索分析
搜索相关的运营指标全部来自前台行为采集,不再单独记录搜索日志:结果页首屏上报一次 cms.search(关键词、结果数、cmsSearchId),翻页沿用同一 cmsSearchId,点击结果记 cms.search_click。因此:
- 搜索需求:搜索次数、独立搜索词、无结果次数与无结果独立词(全量去重,不受排行截断影响)
- 搜索效果:结果点击与搜索点击率;点击后的阅读与转化按「同访客同会话、点击后 30 分钟内」归因到命中的内容
- 无结果搜索词同时是内容选题信号,可在工作台一键转为编辑事项(来源=无结果搜索)
采集口径、指标定义与后台页面见行为采集与访问统计。Redis ZSET(cms:hotwords:{siteId})仍用于「检索管理 → 搜索热词」的实时热度与热词运营清单。