1. 程式人生 > >網頁去重之Simhash演算法

網頁去重之Simhash演算法

Simhash演算法是Google應用在網頁去重中的一個常用演算法,在開始講解Simhash之前,先了解——什麼是網頁去重?為什麼要進行網頁去重?如何進行網頁去重,其基本框架是什麼?   網頁去重,顧名思義,就是過濾掉重複的網頁。統計結果表明,近似重複網頁的數量佔網頁總數量的比例較高,即網際網路上有很多的頁面內容是完全一樣的或是相近的(這個不難理解,比如對於某一事件的新聞報道,很多是大同小異的)。基於這一實際情況,所以要進行網頁去重。   那麼如何進行網頁去重呢?這就用到了Simhash演算法。 去重演算法的任務是對海量資料進行處理,通用的網頁去重的基本框架如下。
  • 對於給定的文件,首先通過一定的特徵抽取手段,從文件中抽取出一系列能夠表徵文件主體內容的特徵集合。這一步的關鍵點在於,儘可能保留文件的重要資訊,拋棄無關緊要的資訊。如何判定哪些資訊是重要的,哪些是不重要的,就是演算法研究的重點。
  • 將文件轉換為特徵集合後,由於搜尋引擎所處理的網頁數量數以億計,為了能夠提高計算速度,很多演算法會在特徵集合的基礎上,對資訊進一步壓縮,採用資訊指紋相關演算法,將特徵集合壓縮為新的資料集合(即生成文件指紋),其包含的元素數量遠遠小於特徵集合數量。
  • 把文件壓縮為文件指紋後,即可通過相似性計算來判斷哪些網頁是近似重複頁面。
  概括的說,就是:(1)特徵詞提取 --> (2)生成文件指紋 --> (3)相似性計算    流程圖如下圖所示    接下來,我們具體來說說Simhash演算法的原理。主要是特徵詞提取和生成文件指紋這兩部分
  1. 從文件中提取一組能表徵文章的特徵詞(這裡首先需要利用開源的cppjieba進行分詞),並計算權重(見筆記:利用tf-idf演算法自動提取關鍵詞),得到pair<特徵詞,權重>;
  2. 利用hash函式(這個hash函式利用開源的),將每個特徵詞對映成為固定長度的二進位制數,即雜湊值,得到pair<雜湊值,權重>;
  3. 利用權值(w)對步驟2產生的二進位制數進行改寫,即把權重資訊融入二進位制序列中,變成一個實數向量。假設步驟2中得到的是<100110, w>,那麼經過改寫變成了實數向量(w,-w,-w,w,w,-w);
  4. 每個特徵詞都做了步驟3的改寫後,對一篇文件中的所有特徵詞的實數向量進行累加(即對應位置相加),從而獲得一個代表整個文件的實數向量。假設最後得到的實數向量是(13,108,-22,-5,-32,55)。
  5. 將步驟4得到的實數向量規範化,即將實數向量轉換為二進位制序列,轉換規則為正數變為1,負數變為0。即(13,108,-22,-5,-32,55) --> 110001。最終得到的這個二進位制序列就是本文件的文件指紋。
  流程示意圖如下:   計算得到每一篇文件的文件指紋後,我們就要對文件集合中的所有文件進行相似性計算,把雷同的文件過濾掉。那麼,怎麼進行文件相似性的計算呢?   對於文件A,B,其內容的相似性可以通過A,B對應的文件指紋的相似性程度來體現。即,內容越相似,二進位制序列對應位置相同的位數就越多。而兩個二進位制序列之間的差異被稱為“海明距離”,海明距離越小,表示兩篇文件越相似。一般認為,當海明距離<=3時,兩篇文件就被視為雷同。至此,問題就轉移至——如何求海明距離?   假設文件A的文件指紋是100110,文件B的文件指紋是100011,顯然,有兩個位置上的數不一樣,即海明距離為2。那麼,文件A,B的海明距離具體該如何計算呢? A:100110 B:100011 ^     000101  --> 海明距離為2 通過上面的計算,我們可以知道,求海明距離,實際上是先對兩個二進位制序列進行異或運算(假設運算結果是ret),再對二進位制序列ret求其1的個數。至此,問題又轉移至——如何求一個二進位制序列中"1"的個數?   關於【如何求一個二進位制序列中"1"的個數】這個問題,在此稍作講解,其實這是一個經典而又巧妙的基礎演算法題。   在分析這種演算法前,我們先來看看把一個數減1會發生什麼神奇的事情? 如果一個整數不等於0,那麼該整數的二進位制表示中至少有一位是1。 情況1:假設這個數的二進位制表示的最右邊一位是1,那麼經過減1操作後,最後一位變成了0而其他位不變,也就是最後一位相當於做了取反操作,由1變成0; 情況2:假設這個數的二進位制表示的最後一位是0,而它的最右邊的1 位於第m位,那麼經過減1操作後,第m位由1變成0,而第m位之後的位取反,第m位之前的位保持不變。比如,一個二進位制數1100,減1後,得到1011。   在前面兩種情況中,我們發現,把一個整數減去1,都是把它最右邊的1變成0(假設最右邊的1位於第m位),而第m位右邊若還有0的話,把0變成1,第m位左邊的位保持不變。接下來,我們把一個整數和它減去1的結果做與運算。如 a   = 1100 a-1 = 1011 ret = a & (a-1) = 1000 可見,把一個整數a減去1,再和原整數a做與運算,會把該整數a最右邊的一個1變成0,那麼,一個整數的二進位制序列中有多少個1就可以通過這種方式算出來!   以下是程式碼:
int numOf_1(int n) {
     int cnt = 0;
     while(n){
          ++cnt;
          n = n & (n-1);
     }
     return cnt;
}

 

至此,Simhash演算法就算全部講完了。   【總結】 1、網頁去重的基本框架 (1)特徵詞提取 --> (2)生成文件指紋 --> (3)相似性計算  2、simhash演算法,將一篇文件轉換成二進位制序列來表示 3、文件相似性計算-->計算兩篇文件的海明距離-->計算二進位制序列中"1"的個數  
參考: 1. 《這就是搜尋引擎-核心技術詳解》