如何建立索引

本文節選自《這就是搜索引擎:核心技術詳解》第三章


3.4建立索引

      正如前述章節所述,索引結構如果建立好了,可以增加搜索的速度,那麼給定一個文檔集合,索引是如何建立起來的呢?建立索引的方式有很多種,本節敘述比較實用的三種建立索引的方法。

  3.4.1兩遍文檔遍歷法(2-Pass In-Memory Inversion)

      顧名思義,此種方法需要對文檔集合進行兩遍掃描,圖3-11是這種方法的示意圖。值得注意的一點是:此種方法完全是在內存裏完成索引的創建過程的,而另外兩種方法則是通過內存和磁盤相互配合來完成索引建立任務。

  

            

                                 圖3-11 兩遍文檔遍歷法

   第一遍文檔遍歷

    在第一遍掃描文檔集合時,該方法並沒有立即開始建立索引,而是收集一些全局的統計信息。比如文檔集合包含的文檔個數N,文檔集合內所包含的不同單詞個數M,每個單詞在多少個文檔中出現過的信息DF。將所有單詞對應的DF值全部相加,就可以知道建立最終索引所需內存大小是多少,因爲一個單詞對應的DF值如果是10,說明有10個文檔包含這個單詞,那麼這個單詞對應的倒排列表應該包含10項內容,每一項記載某個文檔的文檔ID和單詞在該文檔對應的出現次數TF。

    在獲得了上述三類信息後,就可以知道最終索引的大小,於是在內存中分配足夠大的空間,用來存儲倒排索引內容。如圖3-11所示,在內存中可以開闢連續存儲區域,因爲第一遍掃描已經獲得了每個單詞的DF信息,所以將連續存儲區劃分成不同大小的“片段”,詞典內某個單詞根據自己對應的DF信息,可以通過指針,指向屬於自己的內存“片段”的起始位置和終結位置,將來在第二遍掃描時,這個單詞對應的倒排列表信息會被填充進入這個片段中。

    綜上所述,第一遍掃描的主要目的是獲得一些統計信息,並根據統計信息分配內存等資源,同時建立好了單詞相對應倒排列表在內存中的位置信息,即主要做些資源準備工作。

第二遍文檔遍歷

    在第二遍掃描的時候,開始真正建立每個單詞的倒排列表信息,即對於某個單詞來說,獲得包含這個單詞的每個文檔的文檔ID,以及這個單詞在文檔中的出現次數TF,這樣就可以不斷填充第一遍掃描所分配的內存空間。當第二遍掃描結束的時候,分配的內存空間正好被填充滿,而每個單詞用指針所指向的內存區域“片段”,其起始位置和結束位置之間的數據就是這個單詞對應的倒排列表。

    經過兩遍掃描完成索引建立後,即可將內存的倒排列表詞典信息寫入磁盤,這樣就完成了建立索引的過程。從上述流程可以看出,索引的構建完全是在內存中完成的,這就要求內存的大小一定要足夠大,否則如果文檔集合太大時,內存未必能夠滿足需求。

    從另外一個角度看,在建立索引的過程中,從磁盤讀取文檔並解析文檔基本是最消耗時間的一個步驟,而兩遍掃描法因爲要對文檔集合進行兩遍遍歷,所以從速度上不佔優勢,在實際中採用這種方法的系統並不常見。而下面介紹的兩種方法都是對文檔集合進行一遍掃描,所以在速度方面明顯佔優。


3.4.2排序法(Sort-basedInversion)

     兩遍遍歷法在建立索引過程中,對內存的消耗要求較高,不同的文檔集合包含文檔數量大小不同,其所需內存大小是不確定的。當文檔集合非常大時,可能因內存不夠,導致無法建立索引。排序法對此做出了改進,該方法在建立索引的過程中,始終在內存中分配固定大小的內存,用來存放詞典信息和索引的中間結果,當分配的內存被消耗光的時候,把中間結果寫入磁盤,清空內存裏中間結果所佔內存,以用作下一輪存放索引中間結果的存儲區。這種方法由於只需要固定大小的內存,所以可以對任意大小的文檔集合建立索引(參考圖3-12)。

                                   

                                                               圖3-12 排序法

中間結果內存排序

     圖3-12是排序法在內存中建立索引中間結果的示意圖。讀入文檔後,給文檔進行編號,賦予唯一的文檔ID,並對文檔內容解析。對於文檔中出現的單詞,通過查詞典將單詞轉換爲對應的單詞ID,如果詞典中沒有這個單詞,說明是第一次碰到,則賦予單詞以唯一的單詞ID並插入詞典中。在完成了由單詞映射爲單詞ID過程之後,可以對該文檔內每個單詞建立一個(單詞ID,文檔ID,單詞頻率)三元組,這個三元組就是單詞對應文檔的倒排列表項,將這個三元組追加進入中間結果存儲區末尾。如果文檔內的所有單詞都經過如此處理,形成三元組序列的形式,則該文檔被處理完成,開始依次序處理下一文檔,過程與此類似。

     隨着新的文檔不斷被處理完成,存儲三元組集合的中間結果所佔用的內存會越來越多,詞典裏包含的新單詞也越來越多,當分配的內存定額被佔滿時,該方法對三元組中間結果進行排序。排序的原則是:主鍵是單詞ID,即首先要按照單詞ID由小到大排序。次鍵是文檔ID,即在相同單詞ID的情況下,按照文檔ID由小到大排序。通過以上方式,三元組變成有序形式。爲了騰出內存空間,將排好序的三元組寫入磁盤臨時文件中,這樣就空出內存來進行後續文檔的處理。這裏需要注意的是:在建立索引過程中,詞典是一直存儲在內存中的,每次清空內存只是將中間結果寫入磁盤。隨着處理文檔的加大,詞典佔用的內存會逐漸增加,由於分配內存是固定大小,而詞典佔用內存會越來越大,也就是說,越往後,可用來存儲三元組的空間是越來越少的。

    之所以要對中間結果進行排序,主要是爲了方便後續的處理。因爲每一輪處理都會在磁盤產生一個對應的中間結果文件,當所有文檔處理完成後,在磁盤會有多箇中間結果文件,爲了產生最終的索引,需要對這些中間結果文件合併。圖3-13是如何對中間結果進行合併的示意圖。

 

                                  圖3-13 中間文件合併

 

 合併中間結果

    如圖3-13所示,在合併中間結果的過程中,系統爲每個中間結果文件在內存中開闢一個數據緩衝區,用來存放文件的部分數據。因爲在形成中間結果文件前,已經按照單詞ID和文檔ID進行了排序,所以進入緩衝區的數據已經是有序的。合併過程中,將不同緩衝區中包含的同一個單詞ID的三元組進行合併,如果某個單詞ID的所有三元組全部合併完成,說明這個單詞的倒排列表已經構建完成,則將其寫入最終索引中,同時將各個緩衝區中對應這個單詞ID的三元組內容清空,這樣緩衝區就可以繼續從中間結果文件中讀入後續的三元組來進行下一個單詞的三元組合並。當所有中間結果文件都依次被讀入緩衝區,在合併完成後,就形成了最終的索引文件。



3.4.3歸併法(Merge-basedInversion)

     “排序法”分配固定大小內存來建立索引,所以無論要建索引的文檔集合有多大,都可以通過這種方法完成。但是如上所述,在分配的內存定額被消耗光時,

    “排序法”只是將中間結果寫入磁盤,而詞典信息一直在內存中進行維護,隨着處理文檔越來越多,詞典裏包含的詞典項越來越多,所以佔用內存越來越大,導致後期中間結果可用內存越來越少。“歸併法”對此做出了改進,即每次將內存中數據寫入磁盤時,包括詞典在內的所有中間結果信息都被寫入磁盤,這樣內存所有內容都可以被清空,後續建立索引可以使用全部的定額內存。

     圖3-14是“歸併法”的示意圖。其整體流程和排序法大致相同,也是分爲兩個大的階段,首先在內存裏維護中間結果,當內存佔滿後,將內存數據寫入磁盤臨時文件,第二階段對臨時文件進行歸併形成最終索引。

        

                                   圖3-14 歸併法

 

    儘管整體流程看上去和排序法大致相同,但是在具體實現方式上有較大差異。

    首先,“排序法”在內存中存放的是詞典信息和三元組數據,在建立索引過程中,詞典和三元組數據並沒有直接的聯繫,詞典只是爲了將單詞映射爲單詞ID。而“歸併法”則是在內存中建立一個完整的內存索引結構,相當於對目前處理的文檔子集單獨在內存建立起了一整套倒排索引,和最終的索引相比,其結構和形式是相同的,區別只是這個索引只是部分文檔的索引而非全部文檔的索引。

    其次,在將中間結果寫入磁盤臨時文件時,“歸併法”會將整個內存的倒排索引寫入臨時文件,對於某個單詞的倒排列表,在寫入磁盤文件時,將詞典項放在列表最前端,之後跟隨相應的倒排列表,這樣依次將單詞和對應的倒排列表寫入磁盤文件,隨後徹底清空所佔內存。而“排序法”如上節所述,只是將三元組數據排序後寫入磁盤臨時文件,詞典作爲一個映射表一直存儲在內存中。

     在最後的臨時文件合併爲最終索引過程中,兩者也有差異。“排序法”因爲保存的是有序三元組信息,所以在合併時,是對同一單詞的三元組依次進行合併;而“歸併法”的臨時文件則是每個單詞對應的部分倒排列表,所以在合併時針對每個單詞的倒排列表進行合併,形成這個單詞的最終倒排列表。另外,“歸併法”在最後的合併過程中形成最終的詞典信息。

http://blog.csdn.net/malefactor/article/details/7299933

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章