一、前提条件
- MySQL 版本 ≥ 5.6(InnoDB 引擎从该版本开始支持全文索引,推荐 8.0 对中文分词支持更完善)
- 数据库表引擎必须为
InnoDB,字符集使用utf8mb4 - ThinkPHP 已完成基础安装与数据库连接配置
二、数据库表设计与全文索引创建
1.创建文章表(含全文索引)
针对中文搜索,必须使用 ngram 中文分词解析器,否则默认按空格分词的规则无法适配中文。
CREATE TABLE `article` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '文章ID',
`title` varchar(200) NOT NULL COMMENT '文章标题',
`content` text NOT NULL COMMENT '文章内容',
`create_time` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间',
`status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态 1正常 0禁用',
PRIMARY KEY (`id`),
-- 创建全文索引:字段顺序必须与后续搜索的MATCH字段完全一致
FULLTEXT INDEX `ft_title_content` (`title`, `content`) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
2.已有表添加全文索引
若表已存在,执行以下 SQL 添加索引:
ALTER TABLE `article` ADD FULLTEXT INDEX `ft_title_content` (`title`, `content`) WITH PARSER ngram;
3.中文分词核心配置
MySQL 的 ngram 分词默认最小词长为 2(即仅匹配≥2 个字符的关键词),若需要支持单字搜索:
修改 MySQL 配置文件 my.cnf(或 my.ini):
innodb_ngram_token_size=1
重启 MySQL 服务,重建全文索引生效。
三.创建模型
在 app/model 目录下创建 Article.php,封装全文搜索逻辑:
<?php
namespace app\model;
use think\Model;
class Article extends Model
{
// 对应表名(不含前缀)
protected $name = 'article';
// 主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
// 时间格式
protected $dateFormat = 'Y-m-d H:i:s';
/**
* 全文搜索条件范围
* @param object $query 查询对象
* @param string $keyword 搜索关键字
* @return object
*/
public function scopeKeywordSearch($query, $keyword)
{
if (!empty(trim($keyword))) {
// MATCH字段必须与全文索引的字段、顺序完全一致
// IN BOOLEAN MODE 布尔模式,支持灵活的搜索语法
$query->whereRaw(
"MATCH(title,content) AGAINST(? IN BOOLEAN MODE)",
[trim($keyword)]
);
// 普通场景可使用默认自然语言模式:
// $query->whereRaw("MATCH(title,content) AGAINST(?)", [trim($keyword)]);
}
}
/**
* 附加全文相关性得分(用于排序)
* @param object $query 查询对象
* @param string $keyword 搜索关键字
* @return object
*/
public function scopeWithRelevance($query, $keyword)
{
if (!empty(trim($keyword))) {
$query->field(
"*, MATCH(title,content) AGAINST(? IN BOOLEAN MODE) as relevance",
[trim($keyword)]
);
}
}
}
评论