CodeIgniter本身不支持全文搜索,like()仅为模糊匹配,无法利用索引、无相关度排序、不支持中文分词;必须手动建FULLTEXT索引并用原生SQL调用MATCH AGAINST,中文需启用ngram插件。

CodeIgniter 本身不支持全文搜索,like() 只是模糊匹配,不是全文检索 —— 它查得慢、不排相关度、中文基本搜不到。
为什么 like() 不是全文搜索
你写 $this->db->like('content', $kw),生成的是 WHERE content LIKE '%xxx%'。这会导致:
- MySQL 无法使用 B-Tree 索引(% 开头强制全表扫描)
- 搜 “php” 会命中 “phpstorm”,但不会区分“PHP 教程”和“打php电话”
- 没有词干提取、停用词过滤、相关度评分、布尔逻辑(+ - *)
- 字段含中文时,
LIKE更是靠猜,完全不可控
MySQL FULLTEXT 索引必须手动建,CI 不会帮你加
CodeIgniter 的迁移类(dbforge)和查询构造器都不支持 FULLTEXT 索引创建或 MATCH() AGAINST() 语法。你必须自己执行原生 SQL:
在数据库中运行:
ALTER TABLE `articles` ADD FULLTEXT(`title`, `content`);
注意三点:
- 表引擎必须是
InnoDB(推荐)或MyISAM,MEMORY或CSV不支持 - 字段字符集必须为
utf8mb4,否则中文分词直接失效 - 索引定义的字段顺序(如
title, content)必须和MATCH(title, content)中完全一致,错一个就报Can't find FULLTEXT index matching the column list
在 CI 中安全调用 MATCH() AGAINST()
不能用 where() 或 like(),必须用 $this->db->query() 手写原生 SQL,并严格处理参数:
示例(自然语言模式):
$sql = "SELECT *, MATCH(title, content) AGAINST(? IN NATURAL LANGUAGE MODE) AS score
FROM articles
WHERE MATCH(title, content) AGAINST(? IN NATURAL LANGUAGE MODE)
ORDER BY score DESC";<br>$query = $this->db->query($sql, [$keyword, $keyword]);关键细节:
- 同一个
$keyword要传两次:一次给SELECT计算相关度,一次给WHERE过滤 - 别用字符串拼接关键词,否则有 SQL 注入风险;也别用
escape_str()混合布尔模式(如+php -laravel),因为+和-会被转义成普通字符 - 中文搜索必须额外处理:
InnoDB原生不识别中文分词,需启用ngram插件并重建索引:FULLTEXT INDEX ft_title_content (title, content) WITH PARSER ngram
别踩这些坑
实际部署中最容易被忽略的点:
-
ft_min_word_len默认是 4,搜 “AI” “UI” “Go” 全返回空——改这个值要重启 MySQL,且InnoDB不支持运行时修改 - 建完 FULLTEXT 索引后,已有数据不会自动被索引,必须执行
UPDATE articles SET id=id或重新插入才能触发收录 - 混用
MATCH() AGAINST()和LIKE(比如WHERE MATCH() AGAINST() AND title LIKE '%xxx%')会让优化器放弃全文索引,退化为全表扫描 - 想支持中文,又不想搭 Elasticsearch,
ngram是唯一靠谱的 MySQL 内置方案,但要求 MySQL ≥ 5.7.6,且索引创建语句里必须显式写WITH PARSER ngram


















