MySQL中文全文搜索:PHP简单中文分词函数
October/18th 2008
前段时间研究中文全文搜索,结果发现mysql不支持中文的全文搜索。但是有一些解决办法,就是手动把中文单词用空格分开,然后搜索的时候加上 in boolean mode。 但是这就带来一个问题,就是中文分词。这个是个很大的难题,貌似中科院有个小组就是专门做中文分词技术的。我们用php来分词的话,要实现真正语义上的分词是非常困难的,就算实现了效率也不高。一般情况下,我们采用的是如下方法分词:
比如我们有一句话:你好我是刘春龙 那么我们可以这样来分词: 你好 好我 我是 是刘 刘春 春龙
这样虽然看起来有点傻,但是实际应用起来确实可行,因为我们搜索时候输入的关键词也是按照这个方法分词。 下面有个我自己写的函数,可以实现这种分词。传入三个参数,分别是:
1.需要分词的字符串,必须,英文,标点,数字,汉字,日语等都可以。编码为UTF-8 2.是否返回字符串,可选,默认是。如果传入false,那么将返回一个数组。 3.是否base64_encode中文,可选,默认是。Mysql的全文搜索有个配置是 ft_min_word_len 这个值一般是4,而我们分成的中文词语是两个字,就不会被mysql认为是一个词。而base64_encode过后,词语的长度为8,就不存在最小长度问题了。 base64_encode过后数据量会增大 50%。
注意,这里输入和输出的字符串编码都是UTF-8

function string2words($s,$return_string = true,$encode64 = true)
{
        $re = '';
        //匹配汉字
        if (preg_match_all("/([x{4e00}-x{9fff}]{2,})/u",$s,$ms))
        {
                foreach($ms[0] as $w)
                {
                        //关键部分:分词
                        $l = strlen($w)/3;
                        for($i=0;$i<$l;$i++)
                        {
                                $wi = substr($w,$i*3,6);
                                if (strlen($wi) > 3)
                                {
                                        $re .= ($encode64)?' '.str_replace(',','@',base64_encode($wi)):' '.$wi;
                                }
                        }
                }
        }
        //匹配数字
        if (preg_match_all("/(d+[.]?d+)/",$s,$ms))
        {
                foreach($ms[0] as $wi)
                {
                        if(strlen($wi) >= 2)
                        {
                                $re .= ($encode64)?' '.str_replace(',','@',base64_encode($wi)):' '.$wi;
                        }
                }
                $s = preg_replace("/(d+[.]?d+)/",' ',$s);
        }
        //去掉所有双字节字符
        $s = preg_replace("/([^x{00}-x{ff}]+)/u",' ',$s);
        $re = $s.' '.$re;
        if (!$return_string)
        {
                $re = preg_replace("/([^d])([,.-?n])([^d])/",'$1 $3',$re);
                $re = trim(preg_replace("/[s]{2,}/",' ',$re));
                $arr = explode(' ',$re);
                $re = array();
                foreach($arr as $a)
                {
                        if (strlen($a) >= 2) $re[] = $a;
                }
                return $re;
        }
        else
        {
                $re = trim(preg_replace("/[s,.]{2,}/",' ',$re));
                return $re;
        }
}


6050 read 11 comment(s)
#1
liudanking   2008年10月18号 23:24       回复
最近我也在为看一些搜索方面的东西。分词……似乎设计到自然语言逻辑,比较棘手。
#2
longbill   2008年10月19号 15:53       回复
可以看看海量分词。貌似是mysql的扩展。实现的分词效果非常好。
#3
junedo   2008年10月20号 22:09       回复
我现在做得项目也涉及到分析,用得“极易分此组件”
#4
Guest   2008年11月20号 11:49       回复
好像你写的函数对英文等会优先于中文
#5
longbill   2008年11月21号 00:57       回复
这个优先貌似不影响搜索结果。
#6
apple   2008年12月24号 10:03       回复
晕,这也叫分词?还不如不分!
#7
longbill   2008年12月24号 10:05       回复
虽然分出来的结果不适合人类阅读,但是适合机器处理,而且可以达到比较理想的效果。
#8
Guest   2009年04月16号 00:19       回复
这样分词严重增加数据开销,明显不现实。
#9
longbill   2009年04月16号 16:13       回复
数据只是占空间而已。现在空间已经非常便宜。
#10
放众传媒   2009年11月14号 02:24       回复
最近在搞这个分词,我觉得DEDE那个类好用,PHP+mysql的
#11
rcp   2010年08月08号 13:32       回复
用coreseek修改的sphinx吧
添加新的评论
称呼:*
邮件:*
网站:
内容:

Copyright © Longbill 2008-2025 , Designed by EndTo , Powered by EndCMS