船说 CMS 站内搜索关键词如何优化
学完这篇,你能让船说 CMS 的站内搜索从「只能搜到标题里完全一样的词」变成「多字段匹配、能认近义词、有热搜联想、还能看出用户搜不到什么」,并且知道每一步具体改哪个文件、执行哪条 SQL。
第一步:先确认船说 CMS 现在的搜索是怎么匹配的
这一步要搞明白现有逻辑,不然后面改了也不知道改哪。先测一次搜索:在网站前台搜索框输入「测试」,然后按 F12 打开开发者工具,切到 Network(网络)面板,看请求地址,通常是 index.php/index/search/index.html?keyword=测试 这种形式。
接着去服务器找搜索控制器文件。用宝塔面板打开「文件」,进入网站根目录,船说 CMS 一般在这个路径:
/www/wwwroot/你的域名/application/index/controller/Search.php
(ThinkPHP 3.2 老版本可能是 /Application/Home/Controller/SearchController.php,按实际目录找。)
打开后搜索 keyword,你会看到类似 $where['title'] = ['like', '%'.$keyword.'%']; 的代码。这说明它默认只模糊匹配标题一个字段,不分词、不认同义词——这就是大部分「搜不到」问题的根源。
注意:改任何 PHP 文件前先备份,宝塔里右键文件选「复制」即可,改错了能立刻还原。
第二步:把匹配范围从「标题」扩到「标题+关键词+简介」
这一步要做的,是让用户搜的词只要出现在文章标题、SEO 关键词或简介里就能命中。回到 Search.php,把原来的 $where 那几行替换成 ThinkPHP 5 的写法:
$keyword = trim(input('keyword/s'));
if ($keyword === '') {
$this->error('请输入搜索关键词');
}
$keyword = str_replace(['%', '_'], ['\%', '\_'], $keyword); // 转义通配符
$map['title|keywords|description'] = ['like', '%' . $keyword . '%'];
$list = Db::name('article')->where($map)->order('id desc')->paginate(10);
保存后刷新前台再搜一次,原本搜不到的词(比如只在简介里出现过的词)现在应该能出结果了。
注意:不要直接把
$keyword拼进 SQL 字符串里,一定用参数绑定或Db::name()的链式写法,否则会有 SQL 注入风险。
第三步:加一张同义词表,让「AI」能搜到「人工智能」
这一步解决「用户说的词和文章里写的词不一样」的问题。进入宝塔「数据库」→ phpMyAdmin,选中站点数据库,在 SQL 标签页执行:
CREATE TABLE `cs_search_synonym` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`word` varchar(50) NOT NULL,
`synonym` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `cs_search_synonym` (`word`, `synonym`) VALUES
('AI', '人工智能'), ('AI', 'AI绘画'), ('建站', '网站建设');
然后在 Search.php 里查询前先把同义词查出来,拼成一个词数组:
$words = [$keyword];
$syn = Db::name('search_synonym')->where('word', $keyword)->column('synonym');
$words = array_merge($words, $syn);
$map['title|keywords|description'] = ['like', '%' . implode('%', $words) . '%', 'OR'];
这样用户搜「AI」,标题里写「人工智能」的文章也能被搜出来。
第四步:记录搜索日志,找出用户搜不到的词
这一步是让搜索越用越准。在 phpMyAdmin 建日志表:
CREATE TABLE `cs_search_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` varchar(100) NOT NULL,
`results` int(11) NOT NULL DEFAULT 0,
`ip` varchar(50) DEFAULT NULL,
`addtime` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
在 Search.php 查到结果后插入一条:
Db::name('search_log')->insert([
'keyword' => $keyword,
'results' => count($list),
'ip' => request()->ip(),
'addtime' => time(),
]);
跑一周后,在 phpMyAdmin 里执行下面这条 SQL,就能看到最该补内容的词:
SELECT keyword, COUNT(*) AS c, SUM(results = 0) AS empty_num
FROM cs_search_log GROUP BY keyword ORDER BY empty_num DESC LIMIT 20;
empty_num 高的词,就是用户想找但站里没有的内容,直接按这些词写文章或加同义词。
第五步:前台加搜索联想和热门词
这一步提升点击率。找到搜索页模板,一般在:
/template/当前模板目录/search/index.html
在搜索输入框加 id="kw",然后在页面底部加:
<script>
$('#kw').on('keyup', function(){
$.get('/index.php/index/search/hot.html', {q: $(this).val()}, function(res){
// 把返回的词渲染到下拉框
$('#tips').html(res);
});
});
</script>
后端在 Search.php 增加 hot() 方法,从 cs_search_log 里按 keyword 分组取出现次数前 10 条返回即可。
注意:联想接口返回前记得过滤 HTML 标签,否则会变成 XSS 漏洞。
第六步:URL 与搜索结果页标题的优化
把 ?keyword=xxx 改成伪静态 /search/xxx.html,在宝塔「网站」→「设置」→「伪静态」里加规则,把 search/(.*)\.html 重写到 index.php/index/search/index.html?keyword=$1。同时在搜索控制器顶部用 $this->assign('seo_title', $keyword.'_站内搜索_'.config('site_name'));,让搜索结果页的 title 带上关键词,更容易被搜索引擎收录。
小结
- 先测请求、读 Search.php,确认默认只匹配
title单字段; - 把
$map改成title|keywords|description并转义%、_; - 用
cs_search_synonym表做同义词扩展,用cs_search_log表复盘搜不到的词; - 前台加联想下拉,后端从日志表取热词;
- 伪静态 + 搜索页 title 带关键词,兼顾体验和收录。
原文链接:https://www.gj0.com/thread-695.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。