海量數據類似度計算之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短文本查找

相關文章
相關標籤/搜索