题外话
最近更新文章的频率比较低,所以抓紧抽时间更新一波,要不然有人取关了,啊哈哈。
近日比较开心的一件事情是偶然的机会在开发者头条分享了一篇文章,然后这篇文章目前排在7日热度文章第二,看了下点赞近40、收藏数近200、阅读量近2w,所以更坚定了要写下去和大家一起分享学习的想法。
之前一直在系列输出Redis面试热点相关的文章,本来准备的部分还没看完无法成文,因此本次就暂且跳过了。
今天结合笔者日常工作和大家一起来学习一些偏工程的算法,都是大家很熟悉的场景,想必会有共鸣,开始今天的学习吧!
,通过本文你将了解到以下内容:
- 信息爆炸的日常生活
- 网页去重和局部敏感哈希算法
- simhash算法基本原理和过程分析
- 工程中的去重和聚类实现建议
信息爆炸
从2010年之后移动互联网如火如荼,笔者在2011年的时候还在用只能打电话发短信的那种手机,然而现在几乎每个人手机里的app起码有10-20款,以至于经常有种信息爆炸到头晕的感觉,回顾一下匆匆十年手机里的变化:
以笔者目前正在从事的信息流领域来说,有今日头条、百度App、搜狗搜索app、一点资讯、趣头条等feed软件。
很多时候都是自媒体作者会同时在多个平台发布相同的文章,然后会出现非常多的洗稿文章、抄袭文章等,我们无法杜绝和制止这种行为,但是很多时候需要我们使用技术手段来进行识别并处理,让用户看到最好的形式的文章和资讯。
信息爆炸时代,我们需要一个好的文本去重算法。
网页去重
前面是以信息流为例来说的,但是更早的文本去重场景是网页去重,像谷歌、百度、搜狗这种大型的搜索引擎,必须有一套高效的去重算法,要不然网络蜘蛛将做非常多的无用功,时效性等都无法得到保证,更重要的是用户体验也不好。
研究表明:互联网上近似重复的网页的数量占网页总数量的比例高达29%,完全相同的网页大约占网页总数量的22%。
实际中搜索引擎的去重和排序都非常复杂,本文本着简化的思路来阐述其中的一些要点,无法全面深入,对此表示歉意。
谷歌出品,必属精品,我们来看看地表最强搜索引擎是如果做网页去重呢?
这里就引出了今天要讲的主要内容simhash算法,本质上文本去重算法有很多种,每种算法都有各自的优劣势,本文并不做横向对比,而是直接引出simhash算法进行阐述,对于横向对比感兴趣的读者可以自行查阅相关资料。
局部性敏感哈希
说到hash可能我们第一个想到的是md5这种信息摘要算法,可能两篇文本只有一个标点符号的差距,但是两篇文本A和B的md5值差异就非常大,感兴趣的可以试验一下看看,Linux环境下直接md5sum即可计算。
有时候我们希望的是原本相同的文章做了微小改动之后的哈希值也是相似的,这种哈希算法称为局部敏感哈希LSH(Locality Sensitive Hashing),这样我们就能从哈希值来推断相似的文章。
局部敏感哈希算法使得在原来空间相似的样本集合,进行相关运算映射到特定范围空间时仍然是相似的,这样还不够,还需要保证原来不相似的哈希之后仍然极大概率不相似,这种双向保证才让LSH的应用成为可能。
笔者个人认为LSH常用的用途是判重和聚类,其实这两个作用很相似,比如在信息流中我们在识别到文章相似之后无法拒绝入库,这时候就会做聚类,然后用一个id来串起来很多相似的id,从而实现相似文章的把控和管理。
simhash的基本过程
降维压缩映射
simhash算法可以将一个文本生成为一个64bit的二进制数,这里提一句simhash算法最初貌似并不是谷歌提出来的,而是谷歌应用推广的,所以本文出现的simhash相关的数据也都是基于工程中谷歌提出的simhash网页去重展开的。
谷歌2007年关于simhash的论文: https://www2007.org/papers/paper215.pdf
64bit文本容量
simhash值每个位可以是1或者0,这样就有2^64种可能了,这个有多大呢?
想必聪明的读者一定知道棋盘爆炸理论的故事:
传说西塔发明了国际象棋而使国王十分高兴,他决定要重赏西塔,西塔说:我不要你的重赏,陛下,只要你在我的棋盘上赏一些麦子就行了。
在棋盘的第1个格子里放1粒,在第2个格子里放2粒,在第3个格子里放4粒,在第4个格子里放8粒,依此类推,以后每一个格子里放的麦粒数都是前一个格子里放的麦粒数的2倍,直到放满第64个格子就行了。
看似朴实但是如果真放满64格需要多少麦粒呢?
笔者在网上看了一些相关的资料和大家分享一下:
图片来自网络
总计需要1844.67亿亿颗麦粒,以每颗麦粒0.015g计算大约是2767亿吨,在当今粮食产量的水平下大约需要300多年才能种出来。
幂次爆炸的影响力绝非臆想所能企及的程度的,这个哥们后来不知道是不是被治了欺君之罪了,要是在我国古代那肯定悬了。
说这么多的目的是想表达simhash使用64bit的空间足够,不用有太多的担心。
哈希指纹生成过程分析
我们如何将一个文本转换为64bit数据呢?
主要步骤:在新拿到文本之后需要先进行分词,这是因为需要挑出TopN个词来表征这篇文本,并且分词的权重不一样,可以使用相应数据集的tf-idf值作为分词的权重,这样就分成了带权重的分词结果。
之后对所有分词进行哈希运算获取二值化的hash结果,再将权重与哈希值相乘,获得带权重的哈希值,最后进行累加以及二值化处理,先不要晕,看一张图来大致了解下:
接下来举例详细说明的判重过程,假如我们需要处理的短文本如下(本质上长文本也