3.這就是搜索引擎:核心技術詳解 --- 搜索引擎索引

索引,是實現 單詞---文檔的具體數據結構。
倒排索引:包含 單詞詞典,倒排項,倒排文件。
單詞詞典: 哈希加鏈表,樹形詞典結構。
倒排列表,用來記錄哪些文檔包含了某個單詞。
建立索引:
	1.兩邊文檔遍歷法
	2.排序法
	3.歸併法
動態索引:倒排索引,臨時索引和已刪除文檔列表
索引更新策略:完全重建策略,再合併策略,原地更新策略和混合策略
查詢處理機制:一次一文檔,一次一單詞,跳躍指針
多字段索引:
	1.多索引方式
	2.倒排列表方式
	3.擴展列表方式
短語查詢:
	1.位置信息索引
	2.雙詞索引
	3.短語索引
	4.混合方式
分佈式索引:
	1.按文檔劃分
	2.按單詞劃分


1.索引基礎
	1.單詞-文檔矩陣
		單詞-文檔矩陣是表達兩者之間所具有的一種包含關係的概念模型。列代表文檔,每行代表一個單詞。

		搜索引擎的索引其實就是實現單詞-文檔矩陣的具體數據結構。可以有不同的方式來實現上述概念模型,比如倒排索引,簽名文件,後綴樹等。但是各項實現數據表明,
	  倒排索引是單詞到文檔映射關係的最佳實現方式。

	2.倒排索引的基本概念
		文檔:一般搜索引擎的處理對象是互聯網網頁,而文檔這個概念更泛一些,代表以文本形式存在的存儲對象。
		文檔集合:由若干文檔構成的集合稱爲文檔集合。
		文檔編號:在搜索引擎內部,會爲文檔集合內的每一個文檔賦予一個唯一的內部編號。
		單詞編號:與文檔編號相似,搜素引擎內部以唯一的編號來表徵某個單詞
		倒排索引:倒排索引是實現單詞-文檔矩陣的一種具體存儲形式。通過倒排索引,可以根據單詞快速獲取包含這個單詞的文檔列表。倒排索引主要由兩個部分組成:單詞詞典和
	  倒排文件。
	  	單詞詞典:搜索引擎通常的索引單位是單詞,單詞詞典是由文檔集合中出現過的所有單詞構成的字符串集合,單詞詞典內每條索引項記載單詞本身的一些信息及指向倒排索引列表的指針。
	  	倒排列表:倒排列表記載了出現過某個單詞的所有文檔的文檔列表及單詞在該文檔中出現的位置信息,每條記錄稱爲一個倒排項。根據倒排列表,即可獲知哪些文檔包含某個單詞。
	    倒排文件:所有單詞的倒排列表往往順序的存儲在磁盤的某個文件裏,這個文件即被稱爲倒排文件,倒排文件是存儲倒排索引的物理文件。

	3.倒排索引簡單實例
	  (單詞ID,單詞,文檔頻率,倒排列表(文檔id;詞頻;<位置>))
		有了這個索引系統,搜索引擎可以很方便的響應用戶的查詢,比如輸入"facebook",搜索系統查找倒排索引,從中可以讀出包含這個單詞的文檔,,這些文檔就是提供給用戶的搜索結果,
	  而利用單詞頻率信息,文檔頻率信息即可對這些候選搜索結果進行排序,計算文檔和查詢的相似性,按照相似性得分由高到低排序輸出,此即爲搜索系統的部門內部流程。


2.單詞詞典
	單詞詞典是倒排索引中很重要的組成部分,它用來維護文檔集合中出現過的所有單詞的相關信息,同時用來記載某個單詞對應的倒排列表在倒排文件中的位置信息。在支持搜索時,根據用戶的
  查詢詞,去單詞詞典裏查詢,就能夠獲得相應的倒排列表,並以此作爲後續排序的基礎。
  	對於一個規模很大的文檔集合來說,可能包含幾十萬甚至上百萬的不同單詞,能夠快速定位某個單詞,這直接影響搜索時的響應速度,所以需要高效的數據結構來對單詞此地啊你進行構建和
  查找,常用的數據結構包括哈希加鏈表結構和樹形詞典結構。	  

  1.哈希加鏈表
  	這種詞典結構主要由兩個部分組成,主體部分是哈希表,每個哈希表保存一個指針,指針指向衝突鏈表,在衝突鏈表裏面,相同的哈希值的單詞形成鏈表結構。之所以會有衝突鏈表,是因爲兩個
  不同單詞獲得的相同的哈希值,如果是這樣,在哈希方法裏稱作是一次衝突,可以將相同哈希值的單詞存儲在鏈表裏,以供後續查找。
  	對於某個在文檔中出現的單詞T,首先利用哈希函數獲得其哈希值,之後根據哈希值對應的哈希表讀取其中保存的指針,就找到了對應的衝突鏈表。如果衝突鏈表裏已經存在這個單詞,說明單詞在
  之前解析的文檔中出現過。如果在衝突鏈表裏沒有發現這個單詞,說明單詞是首次碰到,則將其加入衝突鏈表中。通過這種方式,當文檔集合內所有的文檔解析完畢後,相應的詞典結構也就建立起來了。
  	在響應用戶查詢請求時,其過程與建立詞典類似,不同點在於即使詞典裏沒有出現過某個單詞,也不會添加到詞典內。

  2.樹形結構
  	B樹(或者B+樹)是另外一種高效的查找結構。與哈希方式不同,需要字典能夠按照大小順序(數字或者字符序),而哈希方式則無需數據滿足此要求。
  	B樹形成了層級查找結構,中間節點用於指出一定順序範圍的詞典項目存儲在哪個子樹中,起到根據詞典比較大小進行導航的作用,最底層的葉子節點存儲單詞的地址信息,根據這個地址就可以提取出
  單詞字符串。


3.倒排列表
	倒排列表用來記錄有哪些文檔包含了某個單詞。一般在文檔集合裏會有很多文檔包含某個單詞,每個文檔會記錄文檔編號(DocID),單詞在這個文檔中出現的次數(TF)及單詞在文檔中哪些位置出現過的
  等信息,這樣與一個文檔相關的信息被稱作倒排索引項,包含這個單詞的一系列倒排索引項形成了列表結構,這就是某個單詞對應的倒排列表。
  	在實際的搜索引擎中,並不存儲倒排索引項中的實際文檔編號,而是取而代之以文檔編號差值(D-Gap)。文檔編號差值是倒排列表中相鄰兩個倒排索引項文檔編號的差值。之所以要對文檔編號進行差值計算,
  主要原因是爲了更好的對數據進行壓縮,原始文檔編號一般都是大數值,通過差值計算,將有效的將大數值轉換爲小數值,有助於增加數據的壓縮率。


4.建立索引
	1.兩邊文檔遍歷法
		顧名思義,此方法需要對文檔集合進行掃描兩邊。此方法完全是在內存裏完成索引的創建過程的,而另外兩種方法則是通過內存和磁盤互相配合來完成索引建立任務的。

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

		第二遍文檔遍歷
			在第二遍掃描的時候,開始真正建立每個單詞的倒排列表信息,即對某個單詞而言,獲得包含這個單詞的每個文檔的文檔id,以及這個單詞在文檔中出現的次數TF,這樣就
		  可以不斷的填充第一遍掃碼所分配的內存空間。當第二遍掃描結束的時候,分配的內存空間正好被填充滿,而這個單詞用指針指向的內存區域'片段',其實位置和終止位置
		  之間的數據就是這個單詞對應的倒排列表。
		  	經過2遍掃描完成索引建立後,即可將內存的倒排列表和詞典信息寫入磁盤,這樣就完成了建立索引的過程。從另外一個角度看,在建立索引的過程中,從磁盤讀取文檔
		  並解析文檔基本是最消耗時間的一個步驟,而2遍掃描因爲要對文檔集合進行掃描2遍,所以從速度上並不佔優。

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

      	中間結果內存排序
      		讀入文檔後,對文檔進行編號,賦予唯一的文檔id,並對文檔內容進行解析。對於文檔中出現的單詞,通過查詢詞典將單詞轉換爲對應的單詞id,如果詞典中沒有這個單詞,說明
      	  是第一次碰到,則賦予單詞以唯一的單詞id並插入詞典。在完成了由單詞映射爲單詞id的過程中,就可以對該文檔內的每個單詞建立一個(單詞id,文檔id,單詞頻率)三元組,這個
      	  三元組就是單詞對應文檔的倒排列表項,將這個三元組追加進中間結果存儲區域末尾。如果文檔內的所有單詞都經過如果處理,形成三元組序列的形式,則該文檔被處理完成,開始
      	  依次處理下一個文檔。
      	  	隨着新的文檔不斷的被處理完成,存儲三元組集合的中間結果所佔用的內存會越來越大,詞典包含的新單詞也越來越多,當分配的內存定額被佔滿時,該方法對三元組中間結果進行
      	  排序。排序的原則是:主鍵是單詞id,即首先要按照單詞id有小到大排序;次鍵是文檔id,即在相同單詞id的情況下,按照文檔id有小到大排序。通過以上方式,三元組變爲有序形式。
      	  爲了騰出內存,將排序好的三元組寫入到磁盤臨時文件中,這樣就騰出內存來進行後續文檔的處理。這裏需要注意的是:在建立索引的過程中,詞典是一直存儲在內存中的,每次清空
      	  內存只是將中間結果寫入到磁盤。隨着處理文檔的增加,詞典佔用的內存會增加,由於內存分配是固定大小,而詞典佔用內存越來越大,也就說,越往後,可用來存儲三元組的空間是
      	  越來越少的。
      	  	之所以要對中間結果進行排序,主要是爲了方便後續的處理。因爲每一輪處理都會在磁盤產生一個對應的中間結果文件,當所有文檔處理完成後,在磁盤中會有多箇中間結果文件,
      	  爲了產生最終的索引,需要將這些中間結果文件合併。

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

    3.歸併法
    	排序法分配固定大小內存來建立索引,所以無論要建立索引的文檔集合有多大,都可以通過這種方法完成。但是如上所述,在分配的內存定額被消耗光時,排序法只是將中間結果寫入磁盤,
      而詞典信息一直在內存中進行維護,隨着處理的文檔越來越多,詞典包含的詞典項越來越多,所以佔用內存越來越大,導致後期中間結果可用內存越來越少。歸併發對此作出了改進,即每次將
      內存中數據寫入磁盤時,包括詞典在內的所有中間結果信息都被寫入磁盤,這樣內存所有的內容都可以被清空,後續建立索引可以使用全部的定額內存。
      	歸併發大體流程,也分兩個階段,首先在內存裏維護中間結果,當內存佔滿後,將內存數據寫入磁盤臨時文件,第二階段對臨時文件進行歸併並形成最終索引。

      	跟排序法的差異:
      		首先,排序法在內存中存放的是詞典信息和三元組信息,在建立索引的過程中,詞典和三元組數據並沒有直接聯繫,詞典只是爲了將單詞映射爲單詞id。而歸併法則是在內存中建立
      	  一個完整的內存索引結構,相當於對目前處理的文檔子集進行單獨在內存中建立起了一整套排序索引,和最終索引比,其結構和形式是相同的,區別只是這個索引只是部分文檔的索引而
      	  非全部文檔的索引。
      	  	其次,在將中間結果寫入磁盤臨時文件時,歸併法會將整個內存的倒排索引寫入臨時文件。
      	  	在最後的臨時文件合併爲最終索引的過程中,兩者也有差異。排序法因爲保存的是有序三元組信息,所以再合併時,是對同一單詞的三元組依次進行合併;而歸併法的臨時文件則是每個
      	  單詞對應的部分排序列表,所以在合併時針對每個單詞的排序列表進行合併,形成這個單詞的最終倒排列表。另外,歸併法在最後的合併過程中形成最終的詞典信息。

5.動態索引
	如果搜索引擎需要處理的文檔集合是靜態集合,那麼在索引建立好之後,就可以一直用建好的索引響應用戶的查詢請求。但是,在真實環境中,搜索引擎需要處理的文檔集合往往是動態集合,
  即在建立好初始的索引之後,後續不段有新的文檔進入系統,同時原有的文檔集合內有些文檔可能被刪除或者內容被更改。
  	索引系統如何能夠做到實時反應這種變化呢?動態索引可以實現這種實時性要求。在這種索引中,有3個關鍵的索引結構:倒排索引,臨時索引和已刪除文檔列表。
  	倒排索引就是對初始文檔集合建立好的索引結構,一般單詞詞典存儲在內存,對應的倒排索引存儲在磁盤文件中。臨時索引是在內存中實時建立的倒排索引,其結構和前述的倒排索引是一樣的,
  區別在於詞典和倒排列表都在內存中存儲。當有新文檔進入系統的時候,實時解析文檔並將其追加進這個臨時索引結構中。已刪除文檔列表則用來存儲已被刪除文檔的相應文檔id,形成一個文檔
  id列表。這裏需要注意的是:當一篇文檔內容被更改,可以被認爲是舊文檔先被刪除,之後向系統內增加一篇新的文檔,通過這種間接的方式實現對內存更改的支持。
  	當系統發現有新文檔進入時,立即將其加入臨時索引中。有文檔被刪除時,則將其加入刪除文檔隊列。文檔被修改時,則將原先文檔放入刪除隊列,解析後更改的文檔內容,並將其加入臨時
  索引中。通過這種方式滿足實時性的要求。
  	如果用戶輸入查詢請求,則搜索引擎同時從倒排索引和臨時索引中讀取用戶查詢單詞的倒排列表,找到包含用戶查詢的文檔集合,並對兩個結果進行合併,之後利用刪除文檔列表進行過濾,
  將搜索結果中那些已經被刪除的文檔從結果中過濾,形成最終的搜索結果,並返回給用戶。這樣就能夠實現動態環境下的準實時搜索功能。


6.索引更新策略
	動態索引通過在內存中維護臨時索引,可以實現對動態文檔和實時搜索的支持。但是服務器內存總是有限的,隨着新加入系統的文檔越來越多,臨時索引消耗的內存也會隨之增加。
  隨着新加入系統的文檔越來越多,臨時索引消耗的內存也會隨着增加。當最初分配的內存將被使用完時,要考慮將臨時索引的內容更新到磁盤索引中,以釋放內存空間來容納後續的新進
  文檔,此時要考慮合理有效的索引更新策略。
  	常用的索引更新策略有4種:完全重建策略,再合併策略,原地更新策略及混合策略。

  	1.完全重建策略
  		完全重建策略是一個相當直觀的方法,當新增文檔到一個數量,將新增文檔和原先的老文檔進行合併,然後利用前述章節提到的建立索引的方式,對所有文檔重新建立索引。新索引建立
  	  完成後,老的索引被遺棄釋放,之後對用戶查詢的響應完全由新的索引負責。
  	  	因爲重建索引需要較長時間,在進行索引重建的過程中,內容仍然需要維護老的索引,來對用戶的查詢做出響應。只有當新索引完全建立完成後,才能釋放老的索引。
  	  	這種重建策略比較適合小的文檔集合,因爲完全重建索引的代價比較高,但是目前主流商業搜索引擎一般是採用此方式來維護索引的更新的,這與互聯網本身的特性有關。

  	2.再合併策略
  		有新增文檔進入搜索系統時,搜索系統在內存維護臨時倒排索引來記錄其信息,當新增文檔到達一定數量,或者指定大小的內存被消耗完,則把臨時索引和老文檔的倒排索引進行合併,
  	  以生成新的索引。
  	  	在實際的搜索系統中,再合併策略按照以下步驟進行索引內容的更新。
  	  	1.當新增文檔進入系統,解析文檔,之後更新內存中維護的臨時索引,文檔中出現的每個單詞,在其倒排列表末尾追加倒排列表項,這個臨時索引可稱爲增量索引。
  	  	2.一旦增量索引將指定的內存消耗光,此時需要進行一次索引合併,即增量索引和老的倒排索引內容進行合併。

  	3.原地更新策略
  		原地更新策略的基本出發點,可以認爲是試圖改進再合併策略的缺點。也就是說,在索引更新過程中,如果老索引的倒排表沒有變化,可以不需要讀取這些信息,而只對那些倒排列表
  	  變化的單詞進行處理。甚至希望能更進一步:即使老索引的倒排列表發生變化,是否可以只在其末尾進行追加操作,而不需要讀取原先的倒排列表並重寫到磁盤的另一個位置?如果能達到
  	  這個目標,明顯可以大量減少磁盤讀/寫操作,提升系統執行效率。
  	  	爲了達到上述目標,原地更新策略在索引合併時,並不生成新的索引文件,而是直接在原先老的索引文件裏追加操作,將增量索引單詞的倒排列表項追加到老索引相應位置的末尾,這樣就
  	  可以達到上述目標,即只更新增量索引裏出現的單詞相關的信息,其他單詞相關信息不做變動。

  	4.混合策略
  		混合策略的出發點是能夠結合不同索引更新的長處,將不同的索引更新策略混合,以形成更高效的方法。


7.查詢處理
	目前有2種常見的查詢處理機制:一種被稱作一次一文檔方式,另外一種別稱作一次一單詞方式。除了兩種基本的查詢處理過程,還介紹了跳躍指針這種查詢優化過程。

	1.一次一文檔 (先縱向再橫向)
		搜索引擎接收到用戶的查詢後,首先將兩個單詞的倒排列表從磁盤讀入內存。所謂的一次一文檔,就是以倒排列表中包含的文檔爲單位,每次將其中某個文檔與查詢
	  的最終相似性得分計算完畢,然後開始計算另外一個文檔的最終得分,直到所有文檔的得分都計算完畢爲止。

	2.一次一單詞 (先橫向再縱向)
		一次一單詞的計算過程與一次一文檔不同,一次一文檔可以直觀理解爲在單詞一文檔矩陣中,以文檔爲單位,縱向進行分數累計,之後移動到後續文檔接着計算,即
	  計算過程是'先縱向再橫向';而一次一單詞則採取的是'先橫向 再縱向'的方式,即首先將某個單詞對應的倒排列表中的每個文檔id都計算一個部分相似性得分,也就是
	  說,在單詞---文檔矩陣中首先進行橫向移動,在計算完畢某個單詞倒排列表中包含的所有文檔後,接着計算下一個單詞倒排列表中包含的文檔id,即進行縱向計算,如果
	  發現某個文檔id已經有了得分,則在原先得分基礎上進行累加。當所有單詞都處理完畢後,每個文檔最終的相似性得分計算結束,之後按照大小排序,輸出得分最高的k個
	  文檔作爲搜索結果。

	3.跳躍指針
		如果用戶輸入的查詢包含多個查詢詞,搜索引擎一般默認是採取與邏輯來判斷文檔是否滿足要求,即要求相關網頁必須包含所有的查詢詞。很明顯,對應於這種
	  應用場景,一次一文檔的查詢處理方式是比較合適的。對於多詞查詢,找到包含所有查詢詞的文檔,等價於求查詢詞對應的倒排列表的交集。
	  	跳躍指針的基本思想是將一個倒排列表數據化整爲零,切分爲若干個固定大小的數據塊,一個數據塊作爲一組,對於每個數據組,增加元信息來記錄關於這個塊的
	  一些信息,這樣即使是面對壓縮後的倒排列表,在進行倒排列表合併的時候也能有兩個好處:一個好處是無需解壓縮所有的倒排列表項,只解壓部分數據即可;另外
	  一個好處是無需比較任意兩個文檔id,通過這種方式有效節省了計算資源和存儲資源。



8.多字段索引
	在很多實際的搜索應用領域,搜索引擎所要處理的文檔是有一定結構的,即文檔包含明確區分的多個字段。比如'發件人','收件人','標題'等。

	1.多索引方式
		多索引方式針對每個不同的字段,分別建立一個索引,當用戶指定某個字段作爲搜索範圍時,可以從相應的索引裏提取結果。
	2.倒排列表方式
		爲了能夠支持對指定字段的搜索,也可以將字段信息存儲在某個關鍵詞對應的倒排列表內,在倒排列表中每個文檔索引項信息的末尾追加字段信息。
	3.擴展列表方式
		擴展列表方式是實際中應用得比較多的支持多字段索引的方法。這個方法爲每個字段建立一個列表,這個列表記載了每個文檔這個字段對應出現的位置。


9.短語查詢
	短語是很常見的現象,幾個經常連在一起被使用的單詞就構成了短語,比如'你懂的',短語強調單詞之間的順序,有時儘管是相同的單詞,順序顛倒後會產生完全不一樣的含義。
	搜索引擎如何能夠支持短語呢?如果單詞的倒排列表只存儲文檔編號和單詞詞頻信息,其保留的信息是不足以支持短語搜索的,因爲單詞之間的順序關係沒有保留。搜索引擎支持
  短語查詢,本質問題是如何在索引中維護單詞之間的順序關係或者位置信息。比較常見的支持短語查詢的技術包括:位置信息索引,雙詞索引及短語索引這3類。

	1.位置信息索引
	2.雙詞索引
	3.短語索引
	4.混合方式

10.分佈式索引
	當搜索引擎需要處理的文檔集合數量非常龐大的時候,靠單機往往難以承當如此重任,此時需要考慮分佈式解決方案。即每臺機器維護整個索引的一部分,由多臺機器協作完成索引的
  建立和對查詢的響應。至於多臺機器如何分工協作,目前常用的分佈式索引包含兩個方案:按文檔對索引劃分和按單詞對索引劃分。

	1.按文檔劃分
	2.按單詞劃分
	3.兩種方式比較

 

搜索引擎索引:

 

 

 

 

 

 

 

 

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