大数据查重去重方案及性能优化

最近做针对百万级别的数据的去重工作,现抽空写下笔记。

做这个去重,是基于前同事的基础上做改造,原来是用的simHash算法做文本相似计算,上网查了下,simHash算法是相对来说,在大数据领域比较受欢迎的查重算法,话不多说,来一步步说下我的设计之路。

一、先简单介绍下simHash.

传统的Hash算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上仅相当于伪随机数产生算法。传统的hash算法产生的两个签名,如果原始内容在一定概率下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别很大。所以传统的Hash是无法在签名的维度上来衡量原内容的相似度,而SimHash本身属于一种局部敏感哈希算法,它产生的hash签名在一定程度上可以表征原内容的相似度。

“你妈妈喊你回家吃饭,回家罗回家罗” 和 “你妈妈叫你回家吃饭,回家罗回家罗”。

通过simhash计算结果为:

  1000010010101101111111100000101011010001001111100001001011001011

  1000010010101101011111100000101011010001001111100001101010001011

通过传统hash计算为:

0001000001100110100111011011110

1010010001111111110010110011101

 

二、具体的应用

 

2.1 改造前

好了,基本要用的算法有了,接下来就是如何好好利用这个算法,设计一个合理的功能。

一开始我采用的设计是,分批次遍历所有的数据,使用simHash算法,将资源中的文本计算为simHash签名,并将签名分成4段Long,用这4个long片段去资源指纹分析表中用查询比对数据,将所有4个片段中有一个相似的指纹全部取出做海明距离的计算,海明距离小于3的再对文本做相似度计算,得出相似度最大的资源所属的堆号,标记当前资源与其堆号相同,入库。

这样最后分出来的结果就是,相似的数据堆号相同,也就是把所有的数据分成一批一批的,同批的是长得差不多的。

光文字有点难懂,下面上逻辑流程图。

大数据查重去重方案及性能优化_第1张图片

 

根据上面这个思路,进行开发,完成后实际测试中发现,这样设计存在严重的性能问题。因为数据量大,要做多次的数据库读取,数据库插入,数据库查询,所消耗的性能是非常巨大的。经过初步计算,400w条数据,可能就需要跑25小时以上。所以,这个方案,就直接否掉了。

 

2.2 改造后

问题

那么,在大数据的时代,性能是非常重要的,怎么解决,也是很头疼,下面我再讲讲我具体的解决方案,不敢说是最好的,但至少相对来说,把性能提高到一条数据大概2ms左右吧。

基于原有的分堆思路,也就是最后的目的是把相似的数据标记上一个相同的堆号。

那么首先,考虑到的一个问题就是,数据的simHash指纹,如何维护的问题,当对数据做修改的时候相应的simHash应该重新计算。

其次,考虑到性能问题,像做simHash签名和重复分析,其实是两件事,是可以分开来做的,也就是,至少这样,可以把性能压力分散开来。

再来,就是多次读取数据库的问题。

一,要多次读取目标数据;

二、要多次查询分析表,来与当前目标数据做对比,以确定重复对象。

 

对应的解决方案

针对问题一,分量一次读取,首先就是读一次很慢,其次就是数据量大,占内存多。通过搜罗整个百度,发现Mongo有一个神技能可以同时解决速度跟内存问题。那就是使用DBCursor光标。DBCursor光标有点类似指针,使用.next()一个个按顺序读取数据库数据,使用完用close()进行关闭连接。

针对问题二,考虑到要多次查询,光来回的数据库连接交互就非常耗时,更何况还要做查询,即使加了索引做查询,数据量大的时候也是非常慢的。怎么解决?

这个时候,就得在内存跟性能之间权衡。一个simHash存成String类型,加上4个Long,400w条数据其实也就几百M的事,所以当然是选择放在内存里面等候做对比。

但是,使用for+if来做对比?那就真的是浪费内存还耗性能了。

于是我考虑到用hashMap的键值查找,hashMap的键值查找,很好的结合了数组和链表的优势,可以说查询速度是相当相当快的了。

用4个simHash片段作为key,对应的完整的simHash+堆号作为value。在对比的时候进行map.get("key1"),这样就可以在内存中,快速的完成大数据之间的对比。比双for循环这种蠢方法不知道快了多少个等级。

这里我为什么是把simHash切成4个片段而不是3个、5个、6个?

这个要根据自己服务器的能力决定了,片段约多准确率越高、但是相对的就越占内存跟耗性能。

 

通过DBCursor光标和hashMap的使用,其实已经在很大程度上调整了性能问题。那还有一个入库问题,我采用的是当积累到一定量的时候,再做批量入库操作,这样可以省了很多的数据库连接时间。

 

以上纯属我个人的一次数据查重经验,仅做参考,欢迎各位有更好的方案共享。

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(大数据)