Mysql 中文全文索引 案例

Mysql 中文全文索引 案例

在PHP+MySQL构架的网站中,大数据量的全文检索一般都会用到MySQL的FULLTEXT全文索引,通过SELECT…MATCH…AGAINST语句来进行查找。

迄今为止,MySQL对中文全文索引无法正确支持,MySQL是不会识别中文词语的。参照MySQL识别英文单词机制,要建立中文全文索引,暂时的解决方案只有手动将中文分词(以空格的形式将中文词语分开),来将中文转换成MySQL认识的语言。

全中文索引的基本思想如下:

  1. 对插入的要建全文索引的中文数据进行分词;

  2. 将原始数据和分词后的数据都存入数据库中,并以某种方式建立联系;

  3. 在存储分词数据的字段上建立FULLTEXT索引;

  4. 查询时以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 进行的分词。。

FindFullText.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

你可能感兴趣的:(PHP)