之前在折腾微信公众平台的时候,想到去弄一个失物招领的功能,其中失主和“雷锋”会分别向微信号发送一条记录,后台要做的就是匹配两句句子的相似度,然后返回相关的信息,总的来说功能是和搜索引擎差不多了。

方案1

我首先想到的是是否能够利用数据库自身的全文搜索,如MySql的全文搜索功能match...against。但是在使用过程用发现,全文搜索比较适合大型数据集。所以这个pass掉了。

不过有兴趣的朋友可以找下mysql的扩展或者专门的搜索引擎搭配:比如Sphinx+mysql+SphinxSE+mmseg中文分词搜索。

方案2

不久之前看到一篇文章《phthon中文分词》,稍微了解了下分词的原理。

对于一个中文字符串“a1a2a3...an”如何正确的用词语c1,c2..cm表示就是中文分词的任务,也就是说我们要去找寻P(c1c2..cm)最大的分词,按照马尔科夫链的想法就是说我们就是求P(c1)P(c1|c2)P(c1c2|c3)...P(c1c2...cm-1|cm)最大。按照阿卡姆剃刀的想法我们可以假设一个最可能的实现,于是google黑板报的假设就是每个词只跟前面的词有关,于是变为求P(c1)P(c1|c2)P(c2|c3)...P(cm-1|cm)最大。进一步的其实我们可以假设每个词都是相对独立的,也就是求P(c1)P(c2)...P(cm)最大

这样中文分词的功能实现了,记下来就是关键了:如何产生相似度。这里还是附上一篇文章[将小白进行到底] 如何比较两篇文章的相似度

里面说到先将两句子进行分词,统计出所有分词关键词放到一个列表中。

句子A:周杰伦是一个歌手,也是一个叉叉

句子B:周杰伦不是一个叉叉,但是是一个歌手

第一步 分词

句子A : 周杰伦/是/一个/歌手,也/是/一个/叉叉 
句子B: 周杰伦/不/是/一个/叉叉 ,但是/是/一个/歌手 

第二步 汇总关键词

周杰伦,是,不,一个,歌手,也,叉叉,但是

第三步 计算词频和生成词频向量

句子A  [1 , 2 , 0 , 2 , 1 , 1 , 0 , 1]     
句子B  [1 , 2 , 1 , 2 , 1 , 1 , 0 , 1] 

上面的是两个多维向量,所以计算相似度就是比较两个向量的相似度。其中具体的解释大家可以点击这里查看具体说明,都是数学知识了。我就直接给出公式:

不知道,您看到这个公式的时候是啥感想,我是看着有点懵了,数学知识扔了好几年了。但是我们还是要把它转化成编程语言,我python也是只会一点点,所以网上找一段n维向量的余弦值代码:

import math
def cos_dist(a, b):
if len(a) != len(b):
    return None
part_up = 0.0
a_sq = 0.0
b_sq = 0.0
for a1, b1 in zip(a,b):
    part_up += a1*b1
    a_sq += a1**2
    b_sq += b1**2
part_down = math.sqrt(a_sq*b_sq)
if part_down == 0.0:
    return None
else:
    return part_up / part_down

至此,所有准备工作都完成了,剩下的就只是整合代码的事情了。有兴趣的朋友可以看下代码。https://github.com/ineo6/chinese-segmentation

参考资料:

python中文分词

如何比较两篇文章的相似度

更多拓展大家可以到阮一峰看一看