海量数据类似度计算之simhash短文本查找

在前一篇文章 《海量数据类似度计算之simhash和海明距离》 介绍了simhash的原理,你们应该感受到了算法的魅力。可是随着业务的增加 simhash的数据也会暴增,若是一天100w,10天就1000w了。咱们若是插入一条数据就要去比较1000w次的simhash,计算量仍是蛮大,普通PC 比较1000w次海明距离须要 300ms ,和5000w数据比较须要1.8 s。看起来类似度计算不是很慢,还在秒级别。给你们算一笔帐就知道了:html

随着业务增加须要一个小时处理100w次,一个小时为3600 *1000 = 360w毫秒,计算一下一次类似度比较最多只能消耗 360w / 100w = 3.6毫秒。300ms慢吗,慢!1.8S慢吗,太慢了!不少状况你们想的就是升级、增长机器,但有些时候光是增长机器已经解决不了问题了,就算增长机器也不是短期可以解决的,须要考虑分布式、客户预算、问题解决的容忍时间?头大时候要相信人类的智慧是无穷的,泡杯茶,听下轻音乐:)畅想下宇宙有多大,宇宙外面还有什么东西,程序员有什么问题可以难倒呢?java

加上客户还提出的几个,汇总一下技术问题:程序员

  • 一、一个小时须要比较100w次,也就是每条数据和simhash库里的数据比较须要作到3.6毫秒。
  • 二、两条同一时刻发出的文本若是重复也只能保留一条。
  • 三、但愿保留2天的数据进行比较去重,按照目前的量级和将来的增加,2天大概在2000w — 5000w 中间。
  • 四、短文本和长文本都要去重,通过测试长文本使用simhash效果很好,短文本使用simhash 准备度不高。

目前咱们估算一下存储空间的大小,就以JAVA 来讲,存储一个simhash 须要一个原生态 lang 类型是64位 = 8 byte,若是是 Object 对象还须要额外的 8 byte,因此咱们尽可能节约空间使用原生态的lang类型。假设增加到最大的5000w数据, 5000w * 8byte = 400000000byte = 400000000/( 1024 * 1024) = 382 Mb,因此按照这个大小普通PC服务器就能够支持,这样第三个问题就解决了。算法

比较5000w次怎么减小时间呢?其实这也是一个查找的过程,咱们想一想之前学过的查找算法: 顺序查找、二分查找、二叉排序树查找、索引查找、哈希查找。不过咱们这个不是比较数字是否相同,而是比较海明距离,之前的算法并不怎么通用,不过解决问题的过程都是通用的。仍是和之前同样,不使用数学公式,使用程序猿你们都理解的方式。还记得JAVA里有个HashMap吗?咱们要查找一个key值时,经过传入一个key就能够很快的返回一个value,这个号称查找速度最快的数据结构是如何实现的呢?看下hashmap的内部结构:服务器

java hashmap内部结构

若是咱们须要获得key对应的value,须要通过这些计算,传入key,计算key的hashcode,获得7的位置;发现7位置对应的value还有好几个,就经过链表查找,直到找到v72。其实经过这么分析,若是咱们的hashcode设置的不够好,hashmap的效率也不见得高。借鉴这个算法,来设计咱们的simhash查找。经过顺序查找确定是不行的,可否像hashmap同样先经过键值对的方式减小顺序比较的次数。看下图:数据结构

大规模simhash算法优化

存储
一、将一个64位的simhash code拆分红4个16位的二进制码。(图上红色的16位)
二、分别拿着4个16位二进制码查找当前对应位置上是否有元素。(放大后的16位)
三、对应位置没有元素,直接追加到链表上;对应位置有则直接追加到链表尾端。(图上的 S1 — SN)多线程

查找
一、将须要比较的simhash code拆分红4个16位的二进制码。
二、分别拿着4个16位二进制码每个去查找simhash集合对应位置上是否有元素。
二、若是有元素,则把链表拿出来顺序查找比较,直到simhash小于必定大小的值,整个过程完成。分布式

原理
借鉴hashmap算法找出能够hash的key值,由于咱们使用的simhash是局部敏感哈希,这个算法的特色是只要类似的字符串只有个别的位数是有差异变化。那这样咱们能够推断两个类似的文本,至少有16位的simhash是同样的。具体选择16位、8位、4位,你们根据本身的数据测试选择,虽然比较的位数越小越精准,可是空间会变大。分为4个16位段的存储空间是单独simhash存储空间的4倍。以前算出5000w数据是 382 Mb,扩大4倍1.5G左右,还能够接受:)grunt

经过这样计算,咱们的simhash查找过程所有降到了1毫秒如下。就加了一个hash效果这么厉害?咱们能够算一下,原来是5000w次顺序比较,如今是少了2的16次方比较,前面16位变成了hash查找。后面的顺序比较的个数是多少? 2^16 = 65536, 5000w/65536 = 763 次。。。。实际最后链表比较的数据也才 763次!因此效率大大提升!测试

到目前第一点降到3.6毫秒、支持5000w数据类似度比较作完了。还有第二点同一时刻发出的文本若是重复也只能保留一条和短文本相识度比较怎么解决。其实上面的问题解决了,这两个就不是什么问题了。

  • 以前的评估一直都是按照线性计算来估计的,就算有多线程提交类似度计算比较,咱们提供类似度计算服务器也须要线性计算。好比同时客户端发送过来两条须要比较类似度的请求,在服务器这边都进行了一个排队处理,一个接着一个,第一个处理完了在处理第二个,等到第一个处理完了也就加入了simhash库。因此只要服务端加了队列,就不存在同时请求不能判断的状况。
  • simhash如何处理短文本?换一种思路,simhash能够做为局部敏感哈希第一次计算缩小整个比较的范围,等到咱们只有比较700屡次比较时,就算使用咱们以前精准度高计算很慢的编辑距离也能够搞定。固然若是以为慢了,也可使用余弦夹角等效率稍微高点的类似度算法。

参考:
个人数学之美系列二 —— simhash与重复信息识别

原创文章,转载请注明: 转载自LANCEYAN.COM

本文连接地址: 海量数据类似度计算之simhash短文本查找

相关文章
相关标签/搜索