分词算法

分词算法一般有三类:基于字符串匹配、基于语义分析、基于统计。复杂的分词程序会将各种算法结合起来以便提高准确率。

Lucene被很多公司用来提供站内搜索,但是Lucene本身并没有支持中文分词的组件,只是在Sandbox里面有两个组件支持中文分词:ChineseAnalyzer和CJKAnalyzer。

ChineseAnalyzer采取一个字符一个字符切分的方法,例如"我想去北京天安门广场"用ChineseAnalyzer分词后结果为: 我#想#去#北#京#天#安#门#广#场。

CJKAnalyzer则是二元分词法,即将相邻的两个字当成一个词,同样前面那句用CJKAnalyzer分词之后结果为:我想#想去#去北#北京#京天#天安#安门#门广#广场。

这两种分词方法都不支持中文和英文及数字混合的文本分词,例如:IBM T60HKU现在只要11000元就可以买到。用上述两种分词方法建立索引,不管是搜索IBM还是11000都是没办法搜索到的。另外,假如我们使用"服务器"作为关键字进行搜索时,只要文档包含"服务"和"器"就会出现在搜索结果中,但这显然是错误的。因此,ChineseAnalyzer和CJKAnalyzer虽然能够简单实现中文的分词,但是在应用中仍然会感觉到诸多不便。

基于字符串匹配的分词算法用得很多的是正向最大匹配和逆向最大匹配。其实这两种算法是大同小异的,只不过扫描的方向不同而已,但是逆向匹配的准确率会稍微高一些。"我想去北京天安门广场"这句使用最大正向分词匹配分词结果:我#想去#北京#天安门广场。这样分显然比ChineseAnalyzer和CJKAnalyzer来得准确,但是正向最大匹配是基于词典的,因此不同的词典对分词结果影响很大,比如有的词典里面会认为"北京天安门"是一个词,那么上面那句的分词结果则是:我#想去#北京天安门#广场。

如果用"广场"作为关键字进行检索,那么使用后一个词典分出来的便可检索到,而使用前一个的则不行,而事实上应该是不管搜索北京天安门、天安门广场、天安门、广场都能检索到这篇文档。使用全切分可以实现这个想法,同样是那句使用正向全切分分词结果为:我#想去#北京天安门#北京#天安门#天安门广场#广场,这样不管用"北京天安门"、"天安门广场"、"天安门"、"广场"中的哪一个作为关键字搜索都可以搜索到。采取这种分法会在一定程度上提高分词的准确率,但也会出现问题,例如"我要在上海南站上车"这句采用正向全切分结果为:我#要在#上海#海南#南站,分出海南这个词显然是错误的,这属于交叉歧义。这有一篇声称可以检测所有交叉歧义的分词算法论文,我没去实现过,所以不知道真正的效果到底如何。

正如前面所说,基于字符串匹配的分词算法都是依赖于词典的,但是不管再怎么大的词典也未必能完全收录所有词汇,况且不断的有新词出现,还有就是人名的识别,因此分词程序如果能够识别出一些词典中所没有的新词的话,有助于提高分词的准确率。最简单的识别新词的方法可以基于统计,一般来说如果两个字不断重复的出现在一起那么他们组成一个词的频率就比较大。基于单字共现的统计方法计算两个汉字A和B(也可能是三个或更多)的相邻共现概率,当这种概率值大于一定的阀值时,我们就认为这两个字可以组词。经常被用来做新词识别的统计理论有:N - 元模型、后缀数组等。