記得以前有人問過我,網頁去重算法有哪些,我不假思索的說出了余弦向量相似度匹配,但如果是數十億級別的網頁去重呢?這下糟糕了,因為每兩個網頁都需要計算一次向量內積,查重效率太低了!我當時就想:論查找效率肯定是要考慮hash算法,相同字符串的hashcode肯定相同,不同字符串的hashcode卻是大不相同,這也不符合要求啊,會不會存在一種算法能夠使相似字符串的code值也相同或相似呢,於是就找到了Google的網頁去重算法-SimHash。我們在使用SimHash算法前需要根據文檔量級選擇SimHash碼的位數,一般可選32位或者64位。
1主要概念
海明距離:在信息編碼中,兩個合法代碼對應位上編碼不同的位數稱為碼距,又稱海明距離。
注:比如合法代碼長度為8,那么00111100與11110000的海明距離是4,10101111與01101111的海明距離是2,11110000與11110000的海明距離是0.
2算法流程
1)分詞
將文檔分詞,然后為每個詞分配權重(比如可以用tf-idf算法計算權重,但這里需要變換一下算法,將tf-idf值以單調遞增函數映射到一個整數值),舉個例子:我(3)是(2)中國人(5),我(3)熱愛(4)我(3)的(1)祖國(5)。括號中是權重,權重越高表示這個詞在文檔中越重要。接下來需要去掉tf-idf值過低的,這樣會把“的”這種虛詞過濾掉。
2)計算Hash
計算每個詞的Hash值,比如“我”——01001000,“是”——10110011,“中國人”——11001100,“熱愛”——10101010,“祖國”——01011000
3)加權
將詞乘以對應的權值,0用-1代替乘以對應權值,這樣,“我”—— -33-3-33-3-3-3,“是”—— 2-222-2-222,“中國人”—— 55-5-555-5-5,“熱愛”—— 4-44-44-44-4,“祖國”—— -55-555-5-5-5
4)合並
把單詞序列從前到后按位累加,上面累加的結果是3,7,-7,-5,15,-9,-7,-15
5)降維
把第4)步的結果變為0-1串,方法是大於0的—>1,小於0的->0,所以結果是11001000,這樣每篇文檔會得到一個ID
6)比較海明距離
將第5)步得到的結果與已有的每一篇文檔的ID做異或運算,然后求運算結果中1的個數(似曾相識燕歸來啊!),得到海明距離。通常對於長文檔來說,海明距離小於3的會被認為是一篇文檔。對於微博等短文本來說,海明距離可以設置的較大,比如10以內的會被認為是同一篇文檔。
3算法優缺點
優點:
1)算法高效,非常適用於大規模網頁去重
2)算法非常容易使用在MapReduce等分布式計算中
3)對於每篇文檔來說,算法消耗空間非常小
缺點:
1)對於長文檔和短文檔同時存在的情況,只依靠算法本身尚不能完美解決網頁去重的問題
2)對於兩篇看似完全不相關的文檔來說,其海明距離甚至有可能為0,但出現這種情況的概率極小