我是怎麼用跳錶優化搜尋引擎的?

haolujun發表於2017-12-11

前言

對於跳錶,我想大家都不陌生吧,這裡不多解釋,感興趣的小夥伴可以看我的這篇文章:http://www.cnblogs.com/haolujun/archive/2012/12/24/2830683.html。 這段時間在做我們拍搜的優化,今天我就講講我是如何用跳錶優化檢索系統的。

搜尋引擎的夾角餘弦計算

都知道,搜尋引擎利用夾角餘弦計算query與文件的相似度,感興趣的小夥伴可以看我的這篇文章:http://www.cnblogs.com/haolujun/archive/2013/01/08/2847503.html, 這裡面需要計算兩個向量的餘弦值。

假設查詢向量為:$ Q = [q_{1},q_{2},......,q_{n}] $
假設文件向量為:$ D = [d_{1},d_{2},......,d_{n}] $

query與文件的相似度為:$ sim(Q,D) = \frac{QD}{|Q||D|} $ 。這裡面需要Q和D模長相乘做分母,對應分量相乘之和做分子。

模長的計算

對於query可以在每次查詢之前做統一的預處理,在預處理過程中計算模長;對於文件,不能每次查詢都計算一遍模長,這樣效率很低,可以事先在建立索引的時候計算模長並儲存。

向量相乘

在搜尋引擎檢索過程中,首先需要對query進行分詞並得到查詢向量,之後我們用分出的詞從倒排表中拉取文件,不熟悉倒排表的小夥伴可以看這篇文章:http://www.cnblogs.com/haolujun/archive/2013/01/06/2847510.html。 通過倒排拉取出來的只是文件的ID,而文件本身包含的內容其實是以正排的方式儲存的:即key=文件ID,$value=(word_{1}, word_{2}, ....word_{n}) $,實際上為了節省儲存空間,正排只儲存該文件中出現過的詞。而今天的向量相乘就是利用正排與query進行兩個集合的求交計算(向量相乘只對同時出現在query以及文件中的詞進行計算,其它的都計為0),那麼這就引出一個新問題,如何求兩個集合的交集呢?聰明的小夥伴肯定想到了解決辦法:對Q和D分別按照字典序排序,之後求兩個有序列表的交集可以線上性時間內完成,示例程式碼如下:

int i = 0, j = 0;
double sum = 0.0;
while(i < len_q && j < len_doc) {
    if(q[i] < d[j]) {
        i++; 
    } else if(q[i] > d[j]) {
        j++;
    } else {
        sum += sim(q[i], d[j]); 
    }
}

但是,還能再優化這個程式碼麼?答案是肯定的,那就是利用跳錶。

對於搜尋引擎來說,通常query較短,而文件較長,我們估計排完序的文件序列中會有一大段一大段的詞都不在query中,可以直接跳過這些段而不用一一遍歷,這就啟發我們可以用跳錶進行加速,優化程式碼如下:

double sum = 0.0;
int step = ceil(sqrt(len_doc)), i = 0, j = 0;
while(i < len_q && j < len_doc) {
   if(q[i] < d[j]) {
      int k = (j - step + 1) < 0 ? 0 : j - step + 1;
      while(k <= j && d[k] < q[i]) k++;
      if(d[k] == q[i]) {
        sum += sim(i, j); j = k + 1;  i++;
      } else {
        j = k; i++;
      }
    } else if(q[i] > d[j]) {
      j = j + step < len_doc ? j + step : j + 1;
    } else {
      sum += sim(i, j); 
      ++i;
      j = j + step < len_doc ? j + step : j + 1;
    }
  }
}

我們在這裡選擇步長為 $ \sqrt[]{len_{doc}} $只是表示一種理論指導,實際中還需要不斷測試不同的步長從而找到實際最優解。

當然,優化這個問題並不一定用跳錶,如果記憶體足夠大,我們可以為每個文件建立雜湊或者map,這樣只需用O(1)或者 O(log(len_doc))時間判斷文件中是否包含一個詞。

總結

利用簡單的跳錶,加起來不過幾十行程式碼,直接使檢索的效率提高一倍,優化了50%的硬體成本,可以高高興興領取年終獎回家過大年了。 5年前我就研究了跳錶,沒想到5年後的今天我竟然用到了它,所以沒事多看看感興趣的技術、研究一下感興趣的問題對你的將來只有利沒有弊。

相關文章