日期:2014-05-16  浏览次数:20942 次

支持中文的MYSQL全文检索[转]
支持中文的MYSQL全文检索[转]

支持中文的MYSQL全文检索[转] 2008-06-16 16:24 Mysql中文搜索 刘军 目前我国互联网用户数已经突破2.1亿,互联网正在越来越广泛和深刻地影响中国人的生活。在 Web2.0思想的引导下,BBS、blog等社区产品大量增加,越来越多的人加入到网民这个行列中来,也因此导致互联网的信息量呈爆炸式增长,信息检索 就成为了一门新兴而重要的技术。 纵观当前互联网的技术架构,无疑Lamp占据了大半壁江山,中国的形式也是如此,越来越多的公司采用这一技术架构自己的网站,如百度、新浪、雅虎等知名企业都用到了这一技术架构。 然而遗憾的是,中国拥有世界第二的互联网用户数(即将成为第一),但是Lamp中的一大核心MySQL对中文的支持不是太理想。 MySQL3.22后的版本都支持全文搜索,但是仅仅限于英文的全文搜索。当试图在一个含有中文字符(或者其他非单字节字符)的字段中使用全文搜索时,不会得到任何结果,原因就是MySQL不支持中文的全文搜索。 当前使用Lamp的中文站点数不胜数,拿Discuz来说,它目前的搜索功能在从检索的时候还是使用效率很低的like,而用discuz这一系统的 BBS不在少数。全文检索自然就成为了一个需要紧急的处理的问题。 一.前导知识 1. 在MySQL上构造中文全文搜索的主导思想。 MySQL不支持中文全文搜索是因为它只能识别非单字节字符以及中文中没有像英文空格那样对词定界,如果能将中文转换成一种单字节类似英文习惯的存储方式,那么自然就能使用MySQL的全文搜索功能了。 将中文按照汉语使用习惯拆分成词,然后将词中每一个字转换为国标码GB18030,并将这些词用空格连接,这样就能在转换后的这段GB18030编码上进行全文搜索。 2. MySQL全文搜索的语法 SELECT fields list FROM table WHERE MATCH ( col1 , col2 ,...) AGAINST ( expr [ search_modifier ]) search_modifier: { IN BOOLEAN MODE | WITH QUERY EXPANSION } 例如:select * from articles where match(title, body) against(‘北京 奥运’)在字段“title,body”上全文搜索“北京 奥运” 注意,MySQL的全文搜索索引只能建立在Myisam引擎上。 更多的关于search_modifier请查看MySQL手册的全文搜索内容。 3. 中文分词 借助网友hightman的中文分词的php插件。 二.过程实现 1.创建数据库test_fulltext 其中两张表如下 表artilces 字段 类型 整理 属性 Null 默认 额外 操作 id int(11) 否 auto_increment title varchar(255) utf8_general_ci 否 body text utf8_general_ci 否 该表存储了原始的中文信息。 表article_zhcode 字段 类型 整理 属性 Null 默认 额外 操作 id int(11) 否 title varchar(255) utf8_general_ci 否 body text utf8_general_ci 否 表索引 键名 类型 基数 操作 字段 PRIMARY PRIMARY 14 id title FULLTEXT 无 title body 注意:在title和body字段上建立的一个索引,并不是在每个字段上建立索引。 该表的主键id参照articles的主键,该表的title和body保存了articles 2.文章的插入 插入文章时,将原始内容插入到表articles以后,然后使用分词插件将文涨分割为中文词汇,并将这些词汇转换问GB13080的编码插入到 article_zhcode。 使用了如下的代码将文章插入到数据库中 if(isset($_p_addsubmit)){ $time1 = get_microtime(); $_p_body = mb_ereg_replace("\r\n",'
', $_p_body); $sql = "INSERT INTO articles SET title = '{$_p_title}', body = '{$_p_body}'"; mysql_query($sql); $time2 = get_microtime(); $newId = mysql_insert_id(); /** * 分词 */ $splitHandle = getScws(); scws_send_text($splitHandle, $_p_title); $titleKeys = scws_get_result($splitHandle, mb_strlen($_p_title, 'UTF-8')); scws_send_text($splitHandle, $_p_body); $bodyKeys = scws_get_tops($splitHandle, mb_strlen($_p_body, 'UTF-8')); /** * 分词结束 */ /** * 将关键词转换为区位码 */ $tKeyStr = $bKeyStr = ''; foreach ($titleKeys as $titleKey){ $tKeyStr .= zhCode($titleKey['word']) . ' '; } foreach ($bodyKeys as $bodyKey){ $bKeyStr .= zhCode($bodyKey['word']) . ' '; } $sql = "INSERT INTO article_zhcode(id, title, body) VALUES({$newId}, '{$tKeyStr}', '{$bKeyStr}')"; mysql_query($sql); $time3 = get_microtime(); if(!file_exists('performace.txt')){ file_put_contents('performace.txt',"words\ttime1\ttime2\ttimetotal\r\n"); } echo $wc = mb_strlen($_p_title . $_p_body, 'UTF-8') . '
'; echo $time2 - $time1 . '
'; echo $time3 - $time2 . '
'; echo $time3 - $time1 . '
'; file_put_contents('performace.txt', mb_strlen($_p_title . $_p_body, 'UTF-8') . "\t" . $time2 - $time1 . "\t" . $time3 - $time2 . "\t" . $time3 - $time1 ."\r\n", FILE_APPEND); } 在这段代码中使用了几个方法。 scws_send_text(),scws_get_result(), scws_get_tops (),getScws(),zhCode(),其中前三个是hightman网友的分词插件中的,实现了分词的功能。getScws()方法初始化分词插 件的初始化。zhCode()是自己编写的,功能是将中文词转换为GB编码。他们的原型如下: function getScws() { $splitHandle = scws_open(); scws_set_dict($splitHandle, 'd:\software\php\scws\dict.utf8.xdb'); scws_set_rule($splitHandle, 'd:\software\php\scws\rules.utf8.ini'); scws_set_charset($splitHandle, 'utf8'); scws_set_ignore($splitHandle, true); scws_set_multi($splitHandle, true); return $splitHandle; } function zhCode($str) { if(preg_match("/^[a-z0-9 ]+$/i",$str)){ return $str; }else{ $zhCode = ''; $str = iconv('UTF-8', 'GB18030', $str); for($i = 0; $i 3){ scws_send_text($splitHandle, urldecode($_g_keywords)); $keywords = scws_get_tops($splitHandle); foreach ($keywords as $keyword){ $keys .= $keyword['word'] . ' '; $kwStr .= zhCode($keyword['word']) . ' '; } }else{ $keys = urldecode($_g_keywords); $kwStr = zhCode($keys);