海量數據相似度計算之simhash短文本查找

在前一篇文章 《海量數據相似度計算之simhash和海明距離》 介紹了simhash的原理,大家應該感覺到了算法的魅力。但是隨着業務的增長 simhash的數據也會暴增,如果一天100w,10天就1000w了。我們如果插入一條數據就要去比較1000w次的simhash,計算量還是蠻大,普通PC 比較1000w次海明距離需要 300ms ,和5000w數據比較需要1.8 s。看起來相似度計算不是很慢,還在秒級別。給大家算一筆賬就知道了:

隨着業務增長需要一個小時處理100w次,一個小時爲3600 *1000 = 360w毫秒,計算一下一次相似度比較最多隻能消耗 360w / 100w = 3.6毫秒。300ms慢嗎,慢!1.8S慢嗎,太慢了!很多情況大家想的就是升級、增加機器,但有些時候光是增加機器已經解決不了問題了,就算增加機器也不是短時間能夠解決的,需要考慮分佈式、客戶預算、問題解決的容忍時間?頭大時候要相信人類的智慧是無窮的,泡杯茶,聽下輕音樂:)暢想下宇宙有多大,宇宙外面還有什麼東西,程序員有什麼問題能夠難倒呢?

加上客戶還提出的幾個,彙總一下技術問題:

  • 1、一個小時需要比較100w次,也就是每條數據和simhash庫裏的數據比較需要做到3.6毫秒。

  • 2、兩條同一時刻發出的文本如果重複也只能保留一條。

  • 3、希望保留2天的數據進行比較去重,按照目前的量級和未來的增長,2天大概在2000w — 5000w 中間。

  • 4、短文本和長文本都要去重,經過測試長文本使用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算法優化

存儲
1、將一個64位的simhash code拆分成4個16位的二進制碼。(圖上紅色的16位)
2、分別拿着4個16位二進制碼查找當前對應位置上是否有元素。(放大後的16位)
3、對應位置沒有元素,直接追加到鏈表上;對應位置有則直接追加到鏈表尾端。(圖上的 S1 — SN)

查找
1、將需要比較的simhash code拆分成4個16位的二進制碼。
2、分別拿着4個16位二進制碼每一個去查找simhash集合對應位置上是否有元素。
2、如果有元素,則把鏈表拿出來順序查找比較,直到simhash小於一定大小的值,整個過程完成。

原理
借鑑hashmap算法找出可以hash的key值,因爲我們使用的simhash是局部敏感哈希,這個算法的特點是隻要相似的字符串只有個別的位數是有差別變化。那這樣我們可以推斷兩個相似的文本,至少有16位的simhash是一樣的。具體選擇16位、8位、4位,大家根據自己的數據測試選擇,雖然比較的位數越小越精準,但是空間會變大。分爲4個16位段的存儲空間是單獨simhash存儲空間的4倍。之前算出5000w數據是 382 Mb,擴大4倍1.5G左右,還可以接受:)

通過這樣計算,我們的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短文本查找


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章