SimHash是什么
SimHash是Google在2007年發表的論文《Detecting Near-Duplicates for Web Crawling 》中提到的一種指紋生成算法或者叫指紋提取算法,被Google廣泛應用在億級的網頁去重的Job中,作為locality sensitive hash(局部敏感哈希)的一種,其主要思想是降維,什么是降維? 舉個通俗點的例子,一篇若干數量的文本內容,經過simhash降維后,可能僅僅得到一個長度為32或64位的二進制由01組成的字符串,這一點非常相似我們的身份證,試想一下,如果你要在中國13億+的茫茫人海中尋找一個人,如果你不知道這個人的身份證,你可能要提供姓名 ,住址, 身高,體重,性別,等等維度的因素來確定是否為某個人,從這個例子已經能看出來,如果有一個一維的核心條件身份證,那么查詢則是非常快速的,如果沒有一維的身份證條件,可能綜合其他幾個非核心的維度,也能確定一個人,但是這種查詢則就比較慢了,而通過我們的SimHash算法,則就像是給每個人生成了一個身份證,使復雜的事物,能夠通過降維來簡化。
SimHash的工作原理
SimHash算法工作流程圖:


解釋下上圖:
(1)准備一篇文本
(2)過濾清洗,提取n個特征關鍵詞,這步一般用分詞的方法實現,關於分詞,比較常用的有IK,mmseg4j,ansj
(3)特征加權,這一步如果有自己針對某個行業的定義的語料庫時候可以使用,沒有的話,就用分詞后的詞頻即可
(4)對關鍵詞進行hash降維01組成的簽名(上述是6位)
(5)然后向量加權,對於每一個6位的簽名的每一位,如果是1,hash和權重正相乘,如果為0,則hash和權重負相乘,至此就能得到每個特征值的向量。
(6)合並所有的特征向量相加,得到一個最終的向量,然后降維,對於最終的向量的每一位如果大於0則為1,否則為0,這樣就能得到最終的simhash的指紋簽名
一個例子如下:


這里面主要應用到是海明距離。
(1)什么是海明距離
兩個碼字的對應比特取值不同的比特數稱為這兩個碼字的海明距離。在一個有效編碼集中,任意兩個碼字的海明距離的最小值稱為該編碼集的海明距離。舉例如下:10101和00110從第一位開始依次有第一位、第四、第五位不同,則海明距離為3。
(2)海明距離的幾何意義
n位的碼字可以用
n維空間的超立方體的一個頂點來表示。兩個碼字之間的海明距離就是超立方體兩個頂點之間的一條邊,而且是這兩個頂點之間的最短距離。
(3)海明距離的應用場景
用於編碼的檢錯和糾錯
經過SimHash算法提取來的指紋(Simhash對長文本500字+比較適用,短文本可能偏差較大,具體需要根據實際場景測試),最后使用海明距離,求相似,在google的論文給出的數據中,64位的簽名,在海明距離為3的情況下,可認為兩篇文檔是相似的或者是重復的,當然這個值只是參考值,針對自己的應用可能又不同的測試取值
到這里相似度問題基本解決,但是按這個思路,在海量數據幾百億的數量下,效率問題還是沒有解決的,因為數據是不斷添加進來的,不可能每來一條數據,都要和全庫的數據做一次比較,按照這種思路,處理速度會越來越慢,線性增長。
針對這個問題在Google的論文中也提出了對應的思路,根據鴿巢原理(也稱抽屜原理):
桌上有十個蘋果,要把這十個蘋果放到九個抽屜里,無論怎樣放,我們會發現至少會有一個抽屜里面至少放兩個蘋果。這一現象就是我們所說的“抽屜原理”。 抽屜原理的一般含義為:“如果每個抽屜代表一個集合,每一個蘋果就可以代表一個元素,假如有n+1個元素放到n個集合中去,其中必定有一個集合里至少有兩個元素。” 抽屜原理有時也被稱為鴿巢原理。它是組合數學中一個重要的原理。
[1]
道理很簡單,但在把這應用到現實問題中,可是能發揮巨大作用的,這也就是數學的奧妙之處。
針對海量數據的去重效率,我們可以將64位指紋,切分為4份16位的數據塊,根據抽屜原理在海明距離為3的情況,如果兩個文檔相似,那么它必有一個塊的數據是相等的,如圖:


然后將4份數據通過K-V數據庫或倒排索引存儲起來K為16位截斷指紋,V為K相等時剩余的48位指紋集合,查詢時候,精確匹配這個指紋的4個16位截斷,如圖所示:


如此,假設樣本庫,有2^34條數據(171億數據),假設數據均勻分布,則每個16位(16個01數字隨機組成的組合為2^16個)倒排返回的最大數量為
2^34/2^16=2^(34-16)=262144個候選結果,4個16位截斷索引,總的結果為:4*262144=1048576,約為100多萬,通過
這樣一來的降維處理,原來需要比較171億次,現在只需要比較100萬次即可得到結果,這樣以來大大提升了計算效率。
參考文章: