Posts Tagged ‘分词’

SCWS中文分词


20 5月
因为在上一篇文章的末尾提到的,coreseek分词存在的问题,经过详细的测试,比较了原版sphinx和coreseek用同一种配置文件,都不分词索引的情况下,coreseek的速度仍然大幅度落后于原版sphinx,于是决定近期摒弃coreseek,换上原版的sphinx。但这样的话,coreseek提供的mmseg分词在搜索的时候也就无法继续使用了。(当然,除非你愿意2个都装,coreseek另外开端口只为分词服务- -) 基于这种情况,决定另外找一个分词的东东来支持搜索时的调用。使用传说中的Google搜了一下,基本锁定了几个分词的东东。 1. mmseg4j 同样是mmseg的算法,可惜是java版本的,功能上倒是比coreseek出品的那个mmseg要强大,新版本已经支持了max-word的分词方法,也就是“中华人民共和国”会被分成“中华人民 中华 人民 共和国 共和 国”类似这样的,可以说加大了搜索的智能性。 但可惜的是,对于我们这类纯php环境的朋友,要享受这个东东要付出的代价有点大。除了要整套java环境的支持,还要php-java-bridge这类方式的调用,无不让人望而止步啊。尝试了几个小时后,终于放弃抵抗,寻找其他方向去了。 mmseg4j对java的朋友可能会更有用吧,不过它的max-word分词强大程度还有待考量,我在linux下java调用测试的时候,结果也不是太满意,当然可能和词库有关吧,没有继续深究了。 2.ICTCLAS传说中的中科天玑出品,号称xx国际xx分词奖第一名,号称多少多少用户量,反正光环无数啦,虽然有共享版,但如果商用的话,似乎有不菲的费用。张宴自己搞的那套什么分词,也是基于这个东东的,尝试用他官网的demo测试一下,结果服务器链接错误 - -||| 怎么都感觉很有国企的风格啊。。。虽然似乎听起来算法不错,但想到我们最终还是要商用的,基本放弃。 3. SCWS,ftphp出品,ftphp貌似也是个搜索引擎,国人自己弄的?没太了解过反正。不过他的分词是开源的,号称自己是简易免费的分词,本来没抱什么太大希望其实,不过看他官方数据分词速度居然比楼上传说中的xx分词奖第一名的速度还要快。。。于是决定一试。 具体的文档可以参见官网(很详细很强大),下面我自己的一些心得,以备日后查看: 安装没什么花头,看doc的第一节照抄弄就行了,注意版本号换成最新的,然后因为我从来都是utf8的,所以所有gbk的地方替换掉,词库也只用了utf8的。值得注意的是,如果你和我一样要在php中调用的话,建议把php extension那段都做掉,起初我也偷懒想用php的exec去执行命令行就好了,结果比较下来,效率相差2个数量级。。。exec要上百毫秒,而extension只要几毫秒! 而最终xdebug分析下来,用extension的方式分词,比原来coreseek的mmseg也要快了1个数量级,笑~,估计近期就得和coreseek彻底说byebye了。 具体妙用大家自己看吧,maxwords也是支持的,感觉还不错,也可以另外加自己的词典,效率也很高,目前看来很完美。 ————————2010/5/31—————————————— 如果用txt自定义词库的话,第一次运行的时候,scws会自动把它编译成.xdb的格式,放到/tmp中去,也就是说,如果你的词典和我一样很大的话,而php的超时时间设定的又比较小的话,很有可能永远都无法生成出这个词典,也就是说,每次分词都会超时。 所以,建议大家第一次装好后,用命令行运行一下.txt的词库,类似: /usr/local/scws/bin/scws -c utf8 -r /usr/local/scws/etc/rules.utf8.ini -M 1 -i 中华人民共和国南京西路 -d /usr/local/scws/etc/dict.utf8.xdb:/usr/local/scws/etc/words.txt 之后:mv /tmp/scws-193b5b00.xdb /usr/local/scws/etc/ 以后用起来就是直接:  /usr/local/scws/bin/scws -c utf8 -r /usr/local/scws/etc/rules.utf8.ini -M 1 -i 中华人民共和国南京西路 -d /usr/local/scws/etc/dict.utf8.xdb:/usr/local/scws/etc/scws-193b5b00.xdb 这样就算第一次也不会很慢啦~

Coreseek(Sphinx) MMSEG 自制词库(附源码)


21 4月

——菜鸟 Linux 服务器搭建 随笔 连载之九

继上次之后玩弄sphinx后,突然发现,原来她并不支持类似摘要的功能,囧。我还真是后知后觉。起初还难以置信,之后看了官网相应FAQ 后,发现确是如此,看来我被lucene搞混了,还以为都有的呢 - - 小小郁闷了一下,顺便又回头看了下lucene,zendframework的那个纯php的lucene貌似还是不合适,php的效率比较堪忧,另外他还致命的不支持分布式的存储,唉。正纠结是不是要去研究下java lucene的时候,看到一篇文章研究,表明在主键索引的mysql中用主键去搜索,效率还是异常高的,千万级的数据基本是0.0x秒级别的速度。就不知道联表后会如何了,不知道用mysql的view会不会效率慢。另外lucene的索引速度比sphinx要慢9倍之多! 下面是一个简单的词库制作的东东,因为上次听说如果词库里面有重复的词会报错来着, 建个表先: CREATE TABLE IF NOT EXISTS `yoowords` ( `word` varchar(255) NOT NULL, `file` varchar(255) NOT NULL, `freq` int(10) unsigned NOT NULL DEFAULT '1', `type` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`word`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 然后把http://www.sogou.com/labs/dl/w.html和http://wubi.sogou.com/dict/list.php?c=306&page=3自己喜欢的词库txt的下载下来。放到某个目录(我是dict) 导入的php: $link = mysql_connect("fedora2", "sphinx", "sstsst") or die("Could not connect: " . mysql_error()); mysql_select_db('mmseg') or die('Could not select database'); if ($handle = opendir('./dict')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { echo "$file\n"; $lines = file("./dict/$file"); foreach ($lines as $line_num => $line) { $words = (array)explode("\t",$line); $result = mysql_query("SELECT * from yoowords where word = '".$words[0]."'"); if(!mysql_fetch_row($result)){ mysql_query("insert into yoowords values('".$words[0]."','".$file."','".$words[1]."','".$words[2]."')"); } } } } closedir($handle); } 导出的php: $link = mysql_connect("fedora2", "sphinx", "sstsst") or die("Could not connect: " . mysql_error()); mysql_select_db('mmseg') or die('Could not select database'); $filename = 'words.txt'; if (!$handle = fopen($filename, 'x')) { echo "不能打开文件 $filename"; exit; } $result = mysql_query("SELECT * from yoowords"); while($row = mysql_fetch_row($result)){ $words.= preg_replace("/[ \f\n\r\v]/","",$row[0]."\t".$row[2])."\nx:".$row[2]."\n"; } if (fwrite($handle,$words) === FALSE) { echo "不能写入到文件 $filename"; exit; } fclose($handle); 暂时,至此。

Coreseek(Sphinx)中文分词设置,MySql默认编码设置&自动SET NAMES utf8


11 4月

——菜鸟 Linux 服务器搭建 随笔 连载之八

嗯,这两天休息在家,周六基本荒废掉了,不记得干了点什么,今天早上6点多莫名其妙醒了睡不着了,于是断断续续接着弄了点搜索引擎,结果过了会又睡着了,之后醒了就去老婆家陪她了,嗯,现在回家都弄好了,顺便记录一下,再睡一觉估计我就得忘光了,唉,脑子不灵光啊。。。 在开始写搜索引擎相关之前,先记录一段关于mysql编码的设置,现在一般编码全部是utf8了,而每次查询前set names utf8还是很浪费资源的,所以看了下,似乎set names utf8等于是: SET character_set_client = utf8; SET character_set_results = utf8; SET character_set_connection = utf8; 于是查了下,如何默认设置这几个东东utf8,只要在/etc/my.cnf中相应位置加入: [mysqld] default-character-set=utf8 [client] default-character-set=utf8 就可以了。ok,下面继续将搜索引擎,上面的mysql设置对coreseek也是很有用的,也是为用中文分词utf8时所准备的。 (注意,我所有的东西都以utf8为基础讲的,如果你还在用nc的gbk,我会无视你) P.S. 关于mysql的这些文末还有补充(2010/4/12)。 coreseek的中文分词设置很简单, 只需要修改/usr/local/coreseek/etc/csft.conf中的charset_type = zh_cn.utf-8, 同时必须添加一行charset_dictpath = /usr/local/coreseek/dict即可,这一行是字典文件的路径, 要用中文分词,必须设置这两行!缺一不可! 默认的字典文件在coreseek安装文件目录下的mmseg/data/中,复制其中的uni.lib到上面说的dict目录就好了。 如果像我一样索引时报了找不到mmseg.ini文件的错误的话,就复制mmseg安装目录中的src/win32/mmseg.ini到dict目录即可。 下面是自己做字典文件的方法,摘自coreseek官网: (比如使用搜狗的词库改造之类的) mmseg -u unigram.txt 该命令执行后,将会产生一个名为unigram.txt.uni的文件,将该文件改名为uni.lib,完成词典的构造。需要注意的是,unigram.txt 必须为UTF-8编码。 词典文件格式: .... 河 187 x:187 造假者 1 x:1 台北队 1 x:1 湖边 1 ...... 其中,每条记录分两行。其中,第一行为词项,其格式为:[词条]\t[词频率]。需要注意的是,对于单个字后面跟这个字作单字成词的频率,这个频率需要在大量的预先切分好的语料库中进行统计,用户增加或删除词时,一般不需要修改这个数值;对于非单字词,词频率处必须为1。第二行为占位项,是由于LibMMSeg库的代码是从Coreseek其他的分词算法库(N-gram模型)中改造而来的,在原来的应用中,第二行为该词在各种词性下的分布频率。LibMMSeg的用户只需要简单的在第二行处填"x:1"即可。 用户可以通过修改词典文件增加自己的自定义词,以提高分词法在某一具体领域的切分精度,系统默认的词典文件在data/unigram.txt中。 分词 mmseg -d tobe_segment.txt 其中,命令使用‘-d’开关指定词库文件所在的位置,参数dict_dir为词库文件(uni.lib )所在的目录;tobe_segment.txt 为待切分的文本文件,必须为UTF-8编码。如果一切正确,mmseg会将切分结果以及所花费的时间显示到标准输出上。 查到个资料表明,如果要合并某个词库到默认词库的话,直接按格式贴到后面还不够,还必须去掉重复的项,否则会报错,所以明天可能会写个程序合并下默认词库和搜狗词库试试,具体代码(如果有的话)到时候再贴。 下面贴一段暂时没用到,以后可能有用的东东,也是上面自制字典同一个位置的内容: 对特殊短语的支持 由于LibMMSeg是为Sphinx全文搜索引擎设计的,因此其内置了部分搜索引擎切分算法的特性,主要表现在对特殊短语的支持上。 在搜索引擎中,需要处理C++时,如果分词器中没有词组C++,则将被切分为C/x +/x +/x,在进一步的检索中,可能每个词会由于出现的过于频繁而被过滤掉,导致搜索的结果与C++相关度不高不说,也严重影响的全文搜索的速度。在LibMMSeg中,内置对特殊短语的支持。 其输入文件格式如下 // test commit .net => dotnet c# => csharp c++ => cplusplus 其中左侧是待支持的特殊短语,右侧是左侧的特殊短语需要被转换为的短语。这一转换在分词前进行。 可以在行的开头加入'//'作为注释符号,发现符号'//'后,整行将被忽略。 特殊短语词库构造命令: mmseg -b exceptions.txt 其中, 开关'-b'指示mmseg是要构造特殊短语词库;exceptions.txt是用户编辑的特殊短语转换规则。 该命令执行后,将在当前目录下产生一个名为"synonyms.dat"的文件,将该文件放在"uni.lib"同一目录下,分词系统将自动启动特殊短语转换功能。 注意: 1、在启用了该功能后,如果分词系统发现了一个特殊短语,将直接输出其在右侧对应的替换的值; 2、右侧被替换的值,请保证不会被分词器进行切分。(eg. C++ => C# 这个转换的意义不大,并且可能导致C++这个短语永远无法被检索到!) 嗯,暂时就这么多吧。目前为止,中文搜索似乎是ok了,但是用putty直接运行search的时候,返回的中文会是乱码,不知道原因ing,可能用php去调会好,后续有情况再记录。 明天争取合并了词库,并且完成用php查询的实验,如果能完成增量索引的概念则更佳,^ ^ That's all for today. ————————2010/4/12分割线———————— 今天到公司尝试了下php的api之类的,昨天mysql的编码问题其实并没有彻底解决,发现csft.conf里面还是加了 sql_query_pre = SET NAMES utf8 才能正常读中文的东东,于是查了些资料,参考了下公司的mysql设置, 发现,原来mysql4.1.2开始支持一个叫init_connect的参数了,也就是默认链接时运行的语句,只要 [mysqld] init_connect='SET NAMES utf8' 就可以了, 但是,必须注意的是,如果链接mysql的用户是super权限的话,这个设置是无效的!!! 希望和我一样偷懒用root链接的朋友注意了。csft.conf 中换了普通权限的用户后,一切正常了,昨天所有乱码问题全部迎刃而解了。^ ^

貓熊寶寶幼齒園

姜經緯的博客