Jaccard相似度

背景

我们网站有个功能是评价房子的户型的,开放给经纪人使用,但是呢,经纪人为了蹭展示机会,就疯狂的复制粘贴,这样就导致大量无用的信息出现,影响用户体验。之前还好,偶尔有几个人,刷个几十条的算多的了,也就个别处理一下,打电话告知不要做这种操作就结束了。但是最近出现了有预谋有组织的刷榜活动,这就尴尬了,所以必须想办法堵住这种行为。

探索过程

其实之前也想过解决方法,想通过比对文本相似度来做,但是想的有点多,一查资料都是NLP,机器学习之类的。一看就头大,三人小团队,业务都做不过来,还搞AI,想太多了吧。于是也就先放下了。但是呢,之前的调研也给我脑袋里留下了一些必要的概念,比如余弦相似度,逆文档频率等等。
今天遇到这种大量刷的事情又让我想重新思考这方面的解决方法,于是我又查阅了一些资料。最终锁定在余弦相似度和Jaccard相似度上。

简要介绍相似度

这里只阐述我个人的简单的理解,并不是严格的定义。

余弦相似度

把文本向量化之后求向量之间的夹角的余弦值,1说明完全相同,-1说明完全相反。

Jaccard相似度

就是把两个集合的交集除以两个集合的并集。
简单的看集合中的元素是不是大量相同。

解决方案选型

其实我们要应对的问题是经纪人的疯狂复制粘贴。
可能被限制了之后会想着稍微改动一下在发布,而这种情况Jaccard相似度也能很好的处理。只要我设置一个能够接受的相似度阈值就可以灵活控制了。
所以我决定使用Jaccard相似度进行判断即可,从它的计算方法上就可以看出,它只关心相同的元素多不多,也就是说两条评论一样的词是不是很多。

比如我设置阈值为0.5,这意味着什么呢?
就是说他如果复制一条内容有10个字,那么在不删除原来内容的情况下,他要再写10个字以上,并且这些字不能是前面重复的。
是的,你没想错,我就是抛弃了分词,直接以字为单位进行计算。

Jaccard相似度PHP实现

代码出处:https://github.com/angeloskath/php-nlp-tools/blob/master/src/NlpTools/Similarity/JaccardIndex.php

1
2
3
4
5
6
7
8
9
10
11
/**
* The similarity returned by this algorithm is a number between 0,1
*/
public function similarity(&$A, &$B)
{
$a = array_fill_keys($A,1);
$b = array_fill_keys($B,1);
$intersect = count(array_intersect_key($a,$b));
$union = count(array_fill_keys(array_merge($A,$B),1));
return $intersect/$union;
}

代码很简单就不多解释了,需要说明的就是$A$B,他们就是两条文本进行分词之后的数组。

分词就是按字分开就好了。(原本是用结巴分词的,但是太耗时,业务也不是非常需要分词,所以弃用了。)

这样一个简单的文本相似度分析功能就实现了。既不会太Low也不会高大上到难以实现。
作为一个普通的技术人,大部分时候技术是服务于业务的。
而是否去实现某个业务功能,以什么方式实现。更多的时候我们要考虑边际成本和边际收益。

够用就好,不是妥协,而是做出合理的决定。

加载评论框需要科学上网