全文检索
基于 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/stats,权限 cms:stat:view):
- 访问统计 Tab:今日 PV/UV/独立 IP(较昨日增减)、近 7/30/90 天 PV/UV 趋势、内容访问 TOP20(点击直达编辑页)、外部来源域名 TOP10、设备分布(PC/移动/爬虫)
- 搜索分析 Tab:搜索量趋势、热搜词 TOP20(含平均结果数)、无结果搜索词榜(内容选题风向标)
- 采集机制:服务端响应路径埋点(静态命中/Redis 缓存命中/SSR 三路径全覆盖,预览流量不计入),搜索日志在搜索首屏记录一次;统计趋势、内容 TOP 和来源域名默认排除
bot,设备分布保留bot独立项;原始日志保留期由「数据保留」中的cms_search_logs策略控制(默认 90 天)