在PHP+MySQL构架的网站中,大数据量的全文检索一般都会用到MySQL的FULLTEXT全文索引,通过SELECT…MATCH…AGAINST语句来进行查找。
迄今为止,MySQL对中文全文索引无法正确支持,MySQL是不会识别中文词语的。参照MySQL识别英文单词机制,要建立中文全文索引,暂时的解决方案只有手动将中文分词(以空格的形式将中文词语分开),来将中文转换成MySQL认识的语言。
全中文索引的基本思想如下:
对插入的要建全文索引的中文数据进行分词;
将原始数据和分词后的数据都存入数据库中,并以某种方式建立联系;
在存储分词数据的字段上建立FULLTEXT索引;
查询时以SELECT…MATCH…AGAINST的方式在分词字段上搜索,将搜到的行通过前面建立的联系找到原始数据行并返回。
配置数据库连接的基本信息
在FindFullText.class.php类中:
'mysql:host=localhost;dbname=blog;charset=utf8';
$usr = 'root';
$pwd = '123456';
$this->db = new PDO($dsn, $usr, $pwd);
数据库建表:
data_text:
CREATE TABLE `data_text` (
`uuid` char(255) DEFAULT NULL,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`body` longtext,
`author` varchar(255) DEFAULT NULL,
`time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8;
index_text:
CREATE TABLE `index_text` (
`uuid` varchar(255) DEFAULT NULL,
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL,
`body` longtext,
PRIMARY KEY (`id`),
FULLTEXT KEY `title` (`title`,`body`)
) ENGINE=MyISAM AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
网上流传的分词方法有很多,主要有基于算法的(比如二元分词算法,字节交叉切分算法)和基于词库的。基于算法是不必要维护词库的,而词库法则必须维护词库,有可能跟不上词汇的发展。实际上现在很多著名的搜索引擎都使用了多种分词的办法,比如“正向最大匹配”+“逆向最大匹配”,基于统计学的新词识别,自动维护词库等技术。
有兴趣的可以看看hightman的scws的php扩展模块方式。参考http://www.ftphp.com/scws/ 。这个开源分词系统这里不多说,总之利用的是词库来分词,而且最新版的是支持自定义词库的,这对于我们的内部网站来说,词库的维护问题变得简单了,因为新增词汇不会像外部网站那么大,也不需要维护太多。
这里我们使用的是另外一个从网上找来的分词类 phpanalysis.class.php 进行的分词。。
get_fenci()//获取文章段落的中文分词结果
//这里调用分词类
public function get_fenci($teststr)
{
//PhpAnalysis::$loadInit = false;
$pa = new PhpAnalysis('utf-8', 'utf-8', true);
//执行分词
$pa->SetSource($teststr);
//多元切分
$pa->differMax = true;
//新词识别
$pa->unitWord = true;
//歧义处理
$pa->StartAnalysis(true);
//输出结果
return $pa->GetFinallyResult(' ', false);
}
get_uuid()//获取唯一UUID
public function get_uuid($prefix = '')
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars, 0, 8);
$uuid .= substr($chars, 8, 4);
$uuid .= substr($chars, 12, 4);
$uuid .= substr($chars, 16, 4);
$uuid .= substr($chars, 20, 12);
return $prefix . $uuid;
}
add( title, body)//向数据库添加信息,传入文章标题和文章内容
public function add($title, $body)
{
$author = 'root';
$uuid = $this->get_uuid();
$today = date("Y-m-d H:i:s");
$sql = 'INSERT INTO data_text ' . '(uuid,title, body, author, time) ' . 'values ' . "('$uuid','$title', '$body', '$author', '$today')";
//echo $sql;
$this->db->exec($sql);
$index_title = $this->get_fenci($title);
$index_body = $this->get_fenci($body);
$sql_index = 'INSERT INTO index_text ' . '(uuid,title, body) ' . 'values ' . "('$uuid','$index_title', '$index_body')";
$count = $this->db->exec($sql_index);
return $count;
}
search($word)//全文检索功能,传入要搜索的关键字
public function search($word)
{
$word = $this->get_fenci($word);
$sql = "SELECT A.title, A.body,A.id, author, time
FROM data_text as A,index_text as B
WHERE A.uuid = B.uuid
AND MATCH (B.title, B.body) AGAINST ('".$word."')";
$sth = $this->db->query($sql);
$result = $sth->fetchALL(PDO::FETCH_ASSOC);
return $result;
}
项目源码地址:
https://github.com/dividez/fulltext