1. 程式人生 > >海量資料處理專題(八)——倒排索引(搜尋引擎之基石)(轉)

海量資料處理專題(八)——倒排索引(搜尋引擎之基石)(轉)

引言:

在資訊大爆炸的今天,有了搜尋引擎的幫助,使得我們能夠快速,便捷的找到所求。提到搜尋引擎,就不得不說VSM模型,說到VSM,就不得不聊倒排索引。可以毫不誇張的講,倒排索引是搜尋引擎的基石。

VSM檢索模型

VSM全稱是Vector Space Model(向量空間模型),是IR(Information Retrieval資訊檢索)模型中的一種,由於其簡單,直觀,高效,所以被廣泛的應用到搜尋引擎的架構中。98年的Google就是憑藉這樣的一個模型,開始了它的瘋狂擴張之路。廢話不多說,讓我們來看看到底VSM是一個什麼東東。

在開始之前,我預設大家對線性代數裡面的向量(Vector)有一定了解的。向量是既有大小又有方向的量,通常用有向線段表示,向量有:加、減、倍數、內積、距離、模、夾角的運算。

文件(Document):一個完整的資訊單元,對應的搜尋引擎系統裡,就是指一個個的網頁。

標引項(Term):文件的基本構成單位,例如在英文中可以看做是一個單詞,在中文中可以看作一個詞語。

查詢(Query):一個使用者的輸入,一般由多個Term構成。

那麼用一句話概況搜尋引擎所做的事情就是:對於使用者輸入的Query,找到最相似的Document返回給使用者。而這正是IR模型所解決的問題:

資訊檢索模型是指如何對查詢和文件進行表示,然後對它們進行相似度計算的框架和方法。

舉個簡單的例子:

現在有兩篇文章(Document)分別是 “春風來了,春天的腳步近了” 和 “春風不度玉門關”。然後輸入的Query是“春風”,從直觀上感覺,前者和輸入的查詢更相關一些,因為它包含有2個春,但這只是我們的直觀感覺,如何量化呢,要知道計算機是門嚴謹的學科^_^。這個時候,我們前面講的Term和VSM模型就派上用場了。

首先我們要確定向量的維數,這時候就需要一個字典庫,字典庫的大小,即是向量的維數。在該例中,字典為{春風,來了,春天, 的,腳步,近了,不度,玉門關} ,文件向量,查詢向量如下圖:

VSM模型示例

VSM模型示例

PS:為了簡單起見,這裡分詞的粒度很大。

將Query和Document都量化為向量以後,那麼就可以計算使用者的查詢和哪個文件相似性更大了。簡單的計算結果是D1和D2同Query的內積都是1,囧。當然了,如果分詞粒度再細一些,查詢的結果就是另外一個樣子了,因此分詞的粒度也是會對查詢結果(主要是召回率和準確率)造成影響的。

上述的例子是用一個很簡單的例子來說明VSM模型的,計算文件相似度的時候也是採用最原始的內積的方法,並且只考慮了詞頻(TF)影響因子,而沒有考慮反詞頻(IDF),而現在比較常用的是cos夾角法,影響因子也非常多,據傳Google的影響因子有100+之多。
大名鼎鼎的Lucene專案就是採用VSM模型構建的,VSM的核心公式如下(由cos夾角法演變,此處省去推導過程)

VSM模型公式

VSM模型公式

從上面的例子不難看出,如果向量的維度(對漢語來將,這個值一般在30w-45w)變大,而且文件數量(通常都是海量的)變多,那麼計算一次相關性,開銷是非常大的,如何解決這個問題呢?不要忘記了,我們這節的主題就是 倒排索引,主角終於粉墨登場了!!!

倒排索引

倒排索引非常類似我們前面提到的Hash結構。以下內容來自維基百科:

倒排索引(英語:Inverted index),也常被稱為反向索引置入檔案反向檔案,是一種索引方法,被用來儲存全文搜尋下某個單詞在一個文件或者一組文件中的儲存位置對映。它是文件檢索系統中最常用的資料結構

有兩種不同的反向索引形式:

  • 一條記錄的水平反向索引(或者反向檔案索引)包含每個引用單詞的文件的列表
  • 一個單詞的水平反向索引(或者完全反向索引)又包含每個單詞在一個文件中的位置。

後者的形式提供了更多的相容性(比如短語搜尋),但是需要更多的時間和空間來建立。

由上面的定義可以知道,一個倒排索引包含一個字典的索引和所有詞的列表。其中字典索引中包含了所有的Term(通俗理解為文件中的詞),索引後面跟的列表則儲存該詞的資訊(出現的文件號,甚至包含在每個文件中的位置資訊)。下面我們還採用上面的方法舉一個簡單的例子來說明倒排索引。

例如現在我們要對三篇文件建立索引(實際應用中,文件的數量是海量的):

文件1(D1):中國移動網際網路發展迅速

文件2(D2):移動網際網路未來的潛力巨大

文件3(D3):中華民族是個勤勞的民族

那麼文件中的詞典集合為:{中國,移動,網際網路,發展,迅速,未來,的,潛力,巨大,中華,民族,是,個,勤勞}

建好的索引如下圖:

倒排索引

倒排索引

在上面的索引中,儲存了兩個資訊,文件號和出現的次數。建立好索引以後,我們就可以開始查詢了。例如現在有一個Query是”中國移動”。首先分詞得到Term集合{中國,移動},查倒排索引,分別計算query和d1,d2,d3的距離。有沒有發現,倒排表建立好以後,就不需要在檢索整個文件庫,而是直接從字典集合中找到“中國”和“移動”,然後遍歷後面的列表直接計算。

對倒排索引結構我們已經有了初步的瞭解,但在實際應用中還有些需要解決的問題(主要是由海量資料引起的)。筆者列舉一些問題,並給出相應的解決方案,拋磚以引玉,希望大家可以展開討論:

1.左側的索引表如何建立?怎麼做才能最高效?

可能有人不假思索回答:左側的索引當然要採取hash結構啊,這樣可以快速的定位到字典項。但是這樣問題又來了,hash函式如何選取呢?而且hash是有碰撞的,但是倒排表似乎又是不允許碰撞的存在的。事實上,雖然倒排表和hash異常的相思,但是兩者還是有很大區別的,其實在這裡我們可以採用前面提到的Bitmap的思想,每個Term(單詞)對應一個位置(當然了,這裡不是一個位元位),而且是一一對應的。如何能夠做到呢,一般在文書處理中,有很多的編碼,漢字中的GBK編碼基本上就可以包含所有用到的漢字,每個漢字的GBK編碼是確定的,因此一個Term的”ID”也就確定了,從而可以做到快速定位。注:得到一個漢字的GBK號是非常快的過程,可以理解為O(1)的時間複雜度。

2.如何快速的新增刪除更新索引?

有經驗的碼農都知道,一般在系統的“做加法”的代價比“做減法”的代價要低很多,在搜尋引擎中中也不例外。因此,在倒排表中,遇到要刪除一個文件,其實不是真正的刪除,而是將其標記刪除。這樣一個減法操作的代價就比較小了。

3.那麼多的海量文件,如果儲存呢?有麼有什麼備份策略呢?

當然了,一臺機器是儲存不下的,分散式儲存是採取的。一般的備份儲存3份就足夠了。

好了,倒排索引終於完工了,不足的地方請指正。謝謝