+ -

中文分词

时间:2009-03-07

来源:redaug

在手机上看
手机扫描阅读
MySQL-5.1.30的scws-1.x分词插件
作者:hightman

@Author: hightman <[email protected]>
@Website: http://www.hightman.cn/bbs
@download: http://www.hightman.cn/down/myft-5.1.30-081231.tgz

[ 基本说明 ]

这是以 mysql-5.1.30 为环境开发制作的 mysql 全文检索分词插件。原则上应该适用整个 5.1.x 系列。

mysql 内置的全文检索仅支持 myisam 类型的表,默认的不支持中文分词。本插件依托 scws-1.0.1 分词系统,

scws 是由我开发的免费开源的中文分词系统,纯 C 开发的函数库。安装本插件必须先安装 scws-1.x。

安装本插件后,系统会注册一个名为 scws_parser 的分词器,可以在 mysql 中直接使用它,对于小型全文检索
需求,十分方便。

MyFT 系列之前曾发过布 5.1.11 和 4.0.27 的版本,旧版是简单的分词算法并不理想,建议改为本版。

[ 安装 & 测试]

1. 首先确定您在您的服务器上以源码方式安装了 mysql 5.1.x/ ,
假设您的 mysql-5.1.x 安装在 $prefix 目录 (通常为 /usr/local/mysql5)

务必是源码方式,里头一些自定义函数功能还需要对代码打补丁。

2. 接下来您必须先安装 scws-1.0.x 系统,相关的安装说明及下载文件请访问:
http://www.ftphp.com/scws 假设安装在 $scws_dir 目录(建议为 /usr/local/scws)

注意要同步下载相应的词典档和规则集并放到 $scws_dir/etc 目录中去。
否则相应的字符集词典/规则集文件不存在的话则会自动采用默认的简易分词法。

3. 下载本插件代码:http://www.hightman.cn/down/myft-5.1.30-081231.tgz

4. 下载后将 tgz 文件复制到您安装的 mysql-5.1 的源代码所在目录里,然后解开:

tar xvzf myft-5.1.30-081231.tgz

解开后有一个 scws 目录被放到 plugin/ 目录里
还有一个 myft_scws_udf_5.1.30.patch 补丁文件及本文件 README.myft-hightman

5. 对 mysql 源码打补丁,以支持自定义函数中获取正确的字符集
在 mysql 源码目录执行 patch -p0 < myft_scws_udf_5.1.30.patch 即可

6. 打完补丁后需要重新编译并安装一下 mysql,这不需要重新 configure ,只需在该目录
执行 make ; make install 即可

7. 开始编译 scws 插件,进入到 mysql 源码目录里的 plugin/scws 目录

先配置:./configure --prefix=$prefix --with-scws=$scws_dir
其中 $prefix 为 mysql-5.1.x 的安装目录,$scws_dir 是 scws-1.x 的安装目录

配置完毕执行 make 和 make install
如果没有错误,至此已经安装完成了。

强烈建议您修改 my.cnf 在 [mysqld] 字段里加入 ft_min_word_len = 2
因为默认是 4,太长了点。

8. 这时您需要重启一下 mysql server,运行以下命令:

$prefix/share/mysql/mysql.server restart

9. 开始测试该插件,主要是全文索引的分词插件,下面以 utf8 编码进行测试。
您可以用命令行或 phpMyAdmin 之类的工具执行 SQL 命令,测试中是采用命令行。

1) 连接:mysql -u root -pxxxxx -h localhost

2) 设置字符集:SET NAMES 'utf8';

3) 选用测试库:USE test;

4) 安装插件(只需一次):INSTALL PLUGIN scws_parser SONAME 'libftscws.so';

5) 建表测试(注意 with parser 指令):

CREATE TABLE `test_utf8` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL,
`body` mediumtext,
PRIMARY KEY (`id`),
FULLTEXT KEY `ft_utf8` (`title`,`body`) WITH PARSER scws_parser
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `test_utf8` VALUES (1, 'MySQL Tutorial', 'DBMS stands for DataBase ...');
INSERT INTO `test_utf8` VALUES (2, 'How To Use MySQL Efficiently', 'After you went through a ...');
INSERT INTO `test_utf8` VALUES (3, 'Optimising MySQL', 'In this tutorial we will show ...');
INSERT INTO `test_utf8` VALUES (4, '1001 MySQL Tricks', '1. Never run mysqld as root. 2. ...');
INSERT INTO `test_utf8` VALUES (5, 'MySQL vs. YourSQL', 'In the following database comparison ...');
INSERT INTO `test_utf8` VALUES (6, 'MySQL Security', 'When configured properly, MySQL ...');
INSERT INTO `test_utf8` VALUES (7, '中国测试', '这样可以吗');
INSERT INTO `test_utf8` VALUES (8, '疯狂测中国测试', '这样总应该可以吗');
INSERT INTO `test_utf8` VALUES (9, '中国语言测试', '这样又是行不行呢');
INSERT INTO `test_utf8` VALUES (10, '我爱china', 'china是我的祖国');

6) 测试查询:

-- 第一句因为 mysql 出现的次数太多(默认超过1半)被忽略了
SELECT * FROM test_utf8 WHERE MATCH(title, body) AGAINST ('mysql');
SELECT * FROM test_utf8 WHERE MATCH(title, body) AGAINST ('mysql' IN BOOLEAN MODE);

SELECT * FROM test_utf8 WHERE MATCH(title, body) AGAINST ('中国');
SELECT * FROM test_utf8 WHERE MATCH(title, body) AGAINST ('+中国 -疯狂' IN BOOLEAN MODE);

10. 自定义函数 SCWS_SEGMENT(),将输入的字符串分词并返回以空格相连的字符串;

1) 创建函数(只需一次):CREATE FUNCTION scws_segment RETURNS STRING SONAME 'libftscws.so';

2) 该函数接受至少一个参数,最多四个参数,依次表示:
<要分词的字符串,可为表达式> <复合分词参数 1~15(整型)> <自动将散字二字分词,1或0> <忽略标点符号,1或0>

3) 在返回结果太长(特别是开启 multi的情况下)会被裁断,以 ... 结尾(不必担心!)

4) 测试:
mysql> SELECT SCWS_SEGMENT('我是中国人');
+---------------------------------+
| SCWS_SEGMENT('我是中国人') |
+---------------------------------+
| 我 是 中国人 |
+---------------------------------+
1 row in set (0.00 sec)

mysql> SELECT SCWS_SEGMENT(title) FROM test_utf8;
+-------------------------------+
| SCWS_SEGMENT(title) |
+-------------------------------+
| MySQL Tutorial |
| How To Use MySQL Efficiently |
| Optimising MySQL |
| 1001 MySQL Tricks |
| MySQL vs . YourSQL |
| MySQL Security |
| 中国 测试 |
| 疯狂 测 中国 测试 |
| 中国 语言 测试 |
| 我爱 china |
+-------------------------------+
10 rows in set (0.00 sec)

11. 自定义函数 SCWS_TOPWORDS(),该函数返回字符串中的核心关键词列表;

1) 创建函数(只需一次):CREATE FUNCTION scws_topwords RETURNS STRING SONAME 'libftscws.so';

2) 接受 1~3 个参数,分别为:<字符串> <词数(整数)> <词性包含或排除(字符串)>
词性多个之间用,分隔,以~开头则表示除这些词性以外。。。和 scws 用法一样。

3) 返回结果是由符合条件的关键词及其词性和次数组成,各词之间用空格连接
<词>/<词性>/<词数>

4) 测试:
mysql> SELECT SCWS_TOPWORDS('我是中国人,中国人很有志气');
+----------------------------------------------------------+
| SCWS_TOPWORDS('我是中国人,中国人很有志气') |
+----------------------------------------------------------+
| 中国人/n/2 志气/n/1 |
+----------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT SCWS_TOPWORDS(CONCAT(title, ' ', body)) FROM test_utf8;
+--------------------------------------------------------------------------------------------------+
| SCWS_TOPWORDS(CONCAT(title, ' ', body)) |
+--------------------------------------------------------------------------------------------------+
| DataBase/en/1 Tutorial/en/1 stands/en/1 MySQL/en/1 DBMS/en/1 for/en/1 |
| Efficiently/en/1 through/en/1 After/en/1 MySQL/en/1 went/en/1 How/en/1 Use/en/1 you/en/1 To/en/1 |
| Optimising/en/1 tutorial/en/1 MySQL/en/1 this/en/1 show/en/1 will/en/1 In/en/1 we/en/1 |
| Tricks/en/1 mysqld/en/1 MySQL/en/1 Never/en/1 1001/en/1 root/en/1 run/en/1 as/en/1 |
| comparison/en/1 following/en/1 database/en/1 YourSQL/en/1 MySQL/en/1 the/en/1 In/en/1 vs/en/1 |
| MySQL/en/2 configured/en/1 Security/en/1 properly/en/1 When/en/1 |
| 中国/ns/1 这样/r/1 测试/vn/1 可以/v/1 |
| 中国/ns/1 应该/v/1 疯狂/an/1 这样/r/1 测试/vn/1 可以/v/1 |
| 中国/ns/1 不行/a/1 语言/n/1 这样/r/1 测试/vn/1 又是/n/1 |
| china/en/2 祖国/n/1 我爱/n/1 |
+--------------------------------------------------------------------------------------------------+
10 rows in set (0.00 sec)

12. 全文检索中的停用词表,类似词典和规则集一样放在 $scws_dir/etc 中
分别为:stops.[$charset.]txt
rules.[$charset.]ini
dict.[$charset.]xdb

如果 $charset 没有指定,则默认即为 gbk
rules dict 采用 scws-1.x 的格式, stops.txt 用的是每行一个词即可,自行建立。

   名称:PHPCWS(PHP中文分词扩展)
  协议:New BSD License
  作者:张宴
  网址:http://code.google.com/p/phpcws/
  SVN:http://code.google.com/p/phpcws/source/browse/#svn/trunk/phpcws

  一、PHPCWS 简介

  1、什么是 PHPCWS ?
  PHPCWS 是一款开源的PHP中文分词扩展,目前仅支持Linux/Unix系统。

  PHPCWS 先使用“ICTCLAS 3.0 共享版中文分词算法”的API进行初次分词处理,再使用自行编写的“逆向最大匹配算法”对分词和进行词语合并处理,并增加标点符号过滤功能,得出分词结果。

  ICTCLAS(Institute of Computing Technology, Chinese Lexical Analysis System)是中国科学院计算技术研究所在多年研究工作积累的基础上,基于多层隐马模型研制出的汉语词法分析系统,主要功能包括中文分词;词性标注;命 名实体识别;新词识别;同时支持用户词典。ICTCLAS经过五年精心打造,内核升级6次,目前已经升级到了ICTCLAS3.0,分词精度 98.45%,各种词典数据压缩后不到3M。ICTCLAS在国内973专家组组织的评测中活动获得了第一名,在第一届国际中文处理研究机构SigHan 组织的评测中都获得了多项第一名,是当前世界上最好的汉语词法分析器。

  ICTCLAS 3.0 商业版是收费的,而免费提供的 ICTCLAS 3.0 共享版不开源,词库是根据人民日报一个月的语料得出的,很多词语不存在。所以本人对ICTCLAS分词后的结果,再采用逆向最大匹配算法,根据自己补充的 一个9万条词语的自定义词库(与ICTCLAS词库中的词语不重复),对ICTCLAS分词结果进行合并处理,输出最终分词结果。

  由于 ICTCLAS 3.0 共享版只支持GBK编码,因此,如果是UTF-8编码的字符串,可以先用PHP的iconv函数转换成GBK编码,再用phpcws_split函数进行分词处理,最后转换回UTF-8编码。

  2、PHPCWS 中文分词在线演示

  演示网址:http://blog.s135.com/demo/phpcws/

  3、PHPCWS 分词速度及用途

  初次使用时,Apache 或 php-cgi(FastCGI) 进程,需要加载一次词库到内存中,需要0.0X秒。58字节的一句话——“2009年2月13日,我编写了一款PHP中文分词扩展:PHPCWS 1.0.0。”,分词速度只需0.0003秒。

  PHPCWS 属于《亿级数据的高并发通用搜索引擎架构设计》 的一部分,用作“搜索查询接口”的关键字分词处理。在此架构中,Sphinx索引引擎对于CJK(中日韩)语言支持一元切分,假设【反恐行动是国产主视角 射击网络游戏】这段文字,Sphinx会将其切成【反 恐 行 动 是 国 产 主 视 角 射 击 网 络 游 戏】,然后对每个字建立反向索引。如果用这句话中包含的字组成一个不存在的词语,例如【恐动】,也会被搜索到,所以搜索时,需要加引号,例如搜索【"反恐 行动"】,就能完全匹配连在一起的四个字,不连续的【"恐动"】就不会被搜索到。但是,这样还有一个问题,搜索【"反恐行动游戏"】或【"国产网络游 戏"】就会搜索不到。所以,我在搜索层写了个PHP中文分词扩展,搜索“反恐行动游戏”、“国产网络游戏”,会被PHPCWS中文分词函数分别切分为“反 恐行动 游戏”、“国产 网络游戏”,这时候,用PHP函数给以空格分隔的词语加上引号,去搜索【"反恐行动" "游戏"】或【"国产" "网络游戏"】,就能搜索到这条记录了。由于PHPCWS位于搜索层,中文分词词库发生增、删、改,只需平滑重启一次Web服务器或php-cgi进程即 可,无需重建搜索索引。

  根据上述情况,对于那些采用二元交叉切分的搜索引擎,PHPCWS用在前端搜索层对用户输入的搜索关键字、短语进行分词处理,同样适合。PHPCWS开发的目的正在于此,对于短句、小文本中文分词切分,速度非常之快。

  4、自定义词库

  自定义词库名称为userdict.tch,格式为 Tokyo Cabinet DBM 的 Abstract key-value 内存哈希数据库(key为GBK编码的词语名词,value为词频。目前词频均填1,暂时用不上)。自定义词库的修改在安装步骤中会详细介绍。


  二、PHPCWS 1.0.0 安装步骤

  1、安装 Tokyo Cabinet 数据库:
wget http://tokyocabinet.sourceforge.net/tokyocabinet-1.4.5.tar.gz
tar zxvf tokyocabinet-1.4.5.tar.gz
cd tokyocabinet-1.4.5/
./configure --prefix=/usr/local/tokyocabinet-1.4.5
make && make install
mkdir -p /usr/local/tokyocabinet-1.4.5/lib/static/
cp -f /usr/local/tokyocabinet-1.4.5/lib/*.a /usr/local/tokyocabinet-1.4.5/lib/static/
echo "/usr/local/tokyocabinet-1.4.5/lib" >> /etc/ld.so.conf
/sbin/ldconfig
cd ../

  2、安装 PHPCWS 扩展:
wget http://phpcws.googlecode.com/files/phpcws-1.0.0.tar.gz
tar zxvf phpcws-1.0.0.tar.gz
cd phpcws-1.0.0/
/usr/local/webserver/php/bin/phpize
./configure --with-php-config=/usr/local/webserver/php/bin/php-config --with-tc=/usr/local/tokyocabinet-1.4.5
make && make install
cd ../
  注:其中/usr/local/webserver/php/为您的PHP安装目录。

  3、安装 ICTCLAS 3.0 词库和 PHPCWS 自定义词库(词库汉字编码均为GBK):
cd /usr/local/
wget http://phpcws.googlecode.com/files/phpcws-dict-1.0.0.tar.gz
tar zxvf phpcws-dict-1.0.0.tar.gz
mv phpcws-dict-1.0.0 phpcws

  您可以往自定义词库内增加自己的词语,方法如下:
cd /usr/local/phpcws/

#如果userdict.tch已经被PHP加载,请拷贝一个备份
cp userdict.tch userdict_new.tch

#添加新词语
/usr/local/tokyocabinet-1.4.5/bin/tcamgr put userdict_new.tch 词语一 1
/usr/local/tokyocabinet-1.4.5/bin/tcamgr put userdict_new.tch 词语二 1

查询某个词语是否已经在词库内
/usr/local/tokyocabinet-1.4.5/bin/tcamgr get userdict_new.tch 词语名词

#删除一个词语
/usr/local/tokyocabinet-1.4.5/bin/tcamgr out userdict_new.tch 词语名称

#将修改后的新词库覆盖回原词库
mv userdict_new.tch userdict.tch

#重启您的Apache服务器,或php-cgi(FastCGI)进程。
#例如重启php-cgi(FastCGI)进程:
/usr/local/webserver/php/sbin/php reload
  您可以从搜狗细胞词库网站下载自己需要的行业分类文本词库,整合到PHPCWS自定义词库中。

  4、修改您的php.ini文件,增加以下几行内容:
[phpcws]
extension = "phpcws.so"
phpcws.dict_path = "/usr/local/phpcws"

  5、重启您的Apache服务器,或php-cgi(FastCGI)进程

  6、查看您的phpinfo信息,如果搜索到以下内容,则表明安装成功:

  


  三、PHPCWS 1.0.0 调用方式

  1、PHPCWS扩展拥有一个PHP函数:
  string phpcws_split ( string $text [, string $interpunction ] )

  参数说明:
  $text 为GBK编码的文本内容;

  $interpunction 为可选参数,用来控制是否过滤标点符号。
  ①、值为空时,表示不过滤;

  ②、值为"default"时,过滤掉默认的标点符号,即以下标点符号:
  ,.!!"#¥%&`'()〔〕〈〉《》「」『』〖〗【】.*+,-.。、?…—·ˉˇ¨‘’“”々~‖∶"/:;|〃<=>?@[\]^_`{|} ̄

  ③、值为其他字符串时,表示过滤掉自定义的标点符号,例如值为",.!,。!"即过滤掉半角、全角的逗号、句号、感叹号。

  2、PHP中文分词实例:

  ①、对GBK编码的字符串进行中文分词处理(example_gbk.php):
  1. <?php  
  2. @header('Content-Type: text/html; charset=gb2312');  
  3. $text = "2009年2月13日,我编写了一款PHP中文分词扩展:PHPCWS 1.0.0。";  
  4.   
  5. echo "分词结果为:<BR>";  
  6. $result = phpcws_split($text);  
  7. echo $result . "<BR><BR>";  
  8.   
  9. echo "过滤掉默认标点符号的分词结果为:<BR>";  
  10. $result = phpcws_split($text, "default");  
  11. echo $result . "<BR><BR>";  
  12.   
  13. echo "过滤掉全角逗号与冒号的分词结果为:<BR>";  
  14. $result = phpcws_split($text, ",:");  
  15. echo $result . "<BR><BR>";  
  16. ?>  
<?php @header('Content-Type: text/html; charset=gb2312'); $text = "2009年2月13日,我编写了一款PHP中文分词扩展:PHPCWS 1.0.0。"; echo "分词结果为:<BR>"; $result = phpcws_split($text); echo $result . "<BR><BR>"; echo "过滤掉默认标点符号的分词结果为:<BR>"; $result = phpcws_split($text, "default"); echo $result . "<BR><BR>"; echo "过滤掉全角逗号与冒号的分词结果为:<BR>"; $result = phpcws_split($text, ",:"); echo $result . "<BR><BR>"; ?>
  ②、对UTF-8编码的字符串进行中文分词处理(example_utf8.php):
  1. <?php  
  2. @header('Content-Type: text/html; charset=utf-8');  
  3. $text = "2009年2月13日,我编写了一款PHP中文分词扩展:PHPCWS 1.0.0。";  
  4. $text = iconv("UTF-8", "GBK//IGNORE", $text);  
  5.   
  6. echo "分词结果为:<BR>";  
  7. $result = phpcws_split($text);  
  8. $result = iconv("GBK", "UTF-8//IGNORE", $result);  
  9. echo $result . "<BR><BR>";  
  10.   
  11. echo "过滤掉默认标点符号的分词结果为:<BR>";  
  12. $result = phpcws_split($text, "default");  
  13. $result = iconv("GBK", "UTF-8//IGNORE", $result);  
  14. echo $result . "<BR><BR>";  
  15.   
  16. echo "过滤掉全角逗号与冒号的分词结果为:<BR>";  
  17. $result = phpcws_split($text, ",:");  
  18. $result = iconv("GBK", "UTF-8//IGNORE", $result);  
  19. echo $result . "<BR><BR>";  
  20. ?>  
<?php @header('Content-Type: text/html; charset=utf-8'); $text = "2009年2月13日,我编写了一款PHP中文分词扩展:PHPCWS 1.0.0。"; $text = iconv("UTF-8", "GBK//IGNORE", $text); echo "分词结果为:<BR>"; $result = phpcws_split($text); $result = iconv("GBK", "UTF-8//IGNORE", $result); echo $result . "<BR><BR>"; echo "过滤掉默认标点符号的分词结果为:<BR>"; $result = phpcws_split($text, "default"); $result = iconv("GBK", "UTF-8//IGNORE", $result); echo $result . "<BR><BR>"; echo "过滤掉全角逗号与冒号的分词结果为:<BR>"; $result = phpcws_split($text, ",:"); $result = iconv("GBK", "UTF-8//IGNORE", $result); echo $result . "<BR><BR>"; ?>
  输出结果为:
分词结果为:
2009年 2月 13日 , 我 编写 了 一款 PHP 中文 分词 扩展 : PHPCWS 1.0.0 。

过滤掉默认标点符号的分词结果为:
2009年 2月 13日 我 编写 了 一款 PHP 中文 分词 扩展 PHPCWS 1.0.0

过滤掉全角逗号与冒号的分词结果为:
2009年 2月 13日 我 编写 了 一款 PHP 中文 分词 扩展 PHPCWS 1.0.0 。

  以上两个实例PHP程序文件可以从SVN中获取:
svn checkout http://phpcws.googlecode.com/svn/trunk/php-example/ php-example