发布一个纯PHP的中文关键字自动提取工具
周末的时候看到腾讯的空间里面写日志的时候能自动提取关键字,感觉这个功能非常的好,于是我自己准备也写一个。因为,提取关键字,肯定要涉及分词,现在的分词算法,最好的估计是统计算法,但是实现稍微复杂一点,用PHP的话,性能往往也不够。于是,我一切从简,争取星期天一天能写完这个工具。
我翻了一下最简单的分词,好像就是向前最大匹配。而且如果字典好的话,据说准确率还挺高的。当然,我没有什么好字典,从中科院的分词软件里面,拿了一本字典。大概有10万的词汇量。当然,你可以用其他的字典,但是一定要有词频。
当然,只是简单的分词,算法没有什么好说的,我就说说我写的时候遇到的问题。
1. 字典管理。
本来我想把字典先读成一个PHP Array 来实现,但是,发现内存占用很大,而且非常的慢。这样,即使写出来,也太慢了。于是乎,我想到了给字典设计一个简单的索引。
索引建立的方法是这样的:
1.1 所有的词汇进行排序。
1.2 然后对每个词汇的第一个字,建立索引,放在字典文件的开头。
1.3 索引区后面就是内容,为了方便进行二分查找,所有的项必须对齐,所以某个字下面按照最长的那个词汇进行对齐。
我写了一个工具,把中科院分词的字典,转换成我的格式的字典。
这样,一测试, 发现性能还可以。但是,每秒查询 2000次左右。为了加速这本字典,减少IO的次数。又写了一个类:MFile,先把整个文件读入内存,我发现读取200K,和读取1M的文件,花费的时间差不多,所以自己加载进入内存算了。
这本字典足足让我写了一个下午才搞定(上午我还没有起床)。
2. PHP不支持Unicode,所以,其实,它不把汉字当作一个字,而是两个char。于是,我还显得把文章转换成一个字的数组。这里,
本来不需要这样复杂,但是我为了以后扩展方便,给字加了分类。
define("T_CHINESE", 1); //中文
define("T_SEP", 1 << 1); //分割符合
define("T_NUM", 1 << 2); //数字
define("T_INDEX", 1 << 3); //索引 ① ② ③ ④ ⑤ ⑥ ⑦
define("T_LETTER", 1 << 4); //字母
define("T_WORD", 1 << 5); //正常单词
define("T_OTHER", 1 << 6);
用一个Int 的位,表示一种类型。比如中文数字就是 T_CHINESE | T_NUM
正确区分数字我觉得对提取关键字不是非常的有用。所以,我其实没有对数字进行特殊的处理。这样,我分词的基本思路是:
先根据句子的分割符号,分成子句。如果子句中还有中文和英文的话,那就分成切分中文部分,和切分英文部分。当然,我这个分法还不是非常的合理。我把阿拉伯数字也算成英文了,这点我没有深入去判断,因为数量词一般不会成为文章的关键字。
写完所有的分词部分,已经是晚上11点了。我不得不草草收场了。本来想支持英文的提取,但是,找不到一本有词频的英文字典,所以,只能算了,时间已经很晚了,大家就凑合着用。我估计也没有什么人会用,哈哈。只是,无聊的时候看连续剧,好不如时间这样打发来的快。
下面是一个测试:
真的不知道博客园的同志们是怎么想的,给我了写Javascript的权限,不给我iframe 的权限。害我不得不动态生成iframe。
代码在这里下载,我写代码的习惯不是很好,欢迎大家批评指正。