最近一直在研究 sphinx 的工作機制,在《Sphinx 的介紹和原理探索》簡單地介紹了其工作原理之後,還有很多問題沒有弄懂,比如底層的資料結構和演算法,於是更進一步地從資料結構層面瞭解其工作原理。在網上搜了很多資料,發現沒有很多介紹這方面的文章,後來找到了一本書,《這就是搜尋引擎》,拜讀了本書的第三章,介紹了主流搜尋引擎用的資料結構及其工作原理,sphinx使用的資料結構也是一樣的,用的也是倒排索引。
注:本文不會對sphinx和搜尋引擎嚴格區分開,同一作搜尋引擎看待。
先附圖一枚:
索引基礎
先介紹與搜尋引擎有關的一些基本概念,瞭解這些概念對後續瞭解工作機制非常重要。
單詞-文件矩陣
單詞-文件矩陣是表達兩者之間所具有的一種包含關係的概念模型。如下圖所示,每列代表一個文件,每行代表一個單詞,打對鉤的位置代表包含關係。
從縱向看,可以得知每列代表文件包含了哪些單詞;從橫向看,每行代表了哪些文件包含了某個單詞。搜尋引擎的索引其實就是實現單詞-文件矩陣的具體資料結構。可以有不同的方式來實現上述概念模型,比如倒排索引、簽名檔案、字尾樹等方式。但實驗資料表明,倒排索引是單詞到文件對映關係的最佳實現方式。
倒排索引基本概念
文件(Document):以文字形式存在的儲存物件。如:網頁、Word、PDF、XML等不同格式的檔案。
文件集合(Document Collection):若干文件構成的集合。如:大量的網頁。
文件編號(Document ID):搜尋引擎內部,唯一標識文件的唯一編號。
單詞編號(Word ID):搜尋引擎內部,唯一標識單詞的唯一編號。
倒排索引(Inverted Index):實現單詞–文件矩陣的一種具體儲存形式。倒排索引主要有單詞詞典和倒排檔案組成。
單詞詞典(Lexicon):文件集合中出現過的所有單詞構成的字串集合,單詞詞典內每條索引項記載單 詞本身的一些資訊及指向倒排列表的指標。
倒排列表(PostingList):出現了某個單詞的所有文件的文件列表及單詞在該文件中出現的位置資訊。 列表中每條記錄稱為一個倒排項(Posting)。
倒排檔案(Inverted File):儲存所有單詞的倒排列表的檔案,倒排檔案是儲存倒排索引的物理檔案。
概念之間的關係如圖:.
倒排索引簡單例項
下面舉一個例項,這樣對倒排索引有一個更直觀的感受。
假設文件集合包含5個文件,每個文件內容如下圖所示:
建立的倒排索引如下圖:
單詞ID:記錄每個單詞的單詞編號;
單詞:對應的單詞;
文件頻率:代表再文件集合中有多少個文件包含某個單詞
倒排列表:包含單詞ID及其他必要資訊
TF:單詞在某個文件中出現的次數
POS:單詞在文件中出現的位置
以單詞“加盟”為例,其單詞編號為6,文件頻率為3,代表整個文件集合中有三個文件包含這個單詞,對應的倒排列表為{(2;1;),(3;1;),(5;1;)}
,含義是在文件2,3,5出現過這個單詞,在每個文件的出現過1次,單詞“加盟”在第一個文件的POS是4,即文件的第四個單詞是“加盟”,其他的類似。
這個倒排索引已經是一個非常完備的索引系統,實際搜尋系統的索引結構基本如此。
單詞詞典
單詞詞典用來維護文件集合中出現過的所有單詞的相關資訊,同時用來記載某個單詞對應的倒排列表在倒排檔案中的位置資訊。在查詢時到單詞詞典裡查詢,就能獲得相應的倒排列表,並以此作為後序排序的基礎。
常用資料結構:雜湊加連結串列和樹形詞典結構。
雜湊加連結串列
下圖是雜湊加連結串列詞典結構的示意圖。主體是雜湊表,每個雜湊表項儲存一個指標,指標指向衝突連表,相同雜湊值的單詞形成連結串列結構。
構建過程:
1 2 3 4 5 6 7 |
對文件進行分詞; 對於做好的分詞,利用雜湊函式獲取雜湊值; 根據雜湊值對應的雜湊表項找到對應的衝突連結串列; 如果衝突連結串列已經存在該單詞 不處理 否則 加入衝突連表 |
樹形結構
使用B樹或者B+樹的結構。與雜湊表不同的是,需要字典項能按照大小排序,即使用數字或字元序。 樹形結構中,使用層級查詢,中間節點儲存一定順序範圍的詞典專案儲存在哪個子樹中,最底層的葉子節點儲存單詞的地址資訊。
倒排列表
倒排列表用來記錄哪些文件包含了某個單詞。倒排列表由倒排索引項組成,每個倒排索引項由文件ID,單詞出現次數TD以及單詞在文件中哪些位置出現過等資訊。包含某單詞的一些列倒排索引項形成了某個單詞對應的倒排列表。下圖是倒排列表示意圖:
建立索引
前面介紹了索引結構,那麼,有了資料之後索引是怎麼建立的呢?主要有三種建立索引的方法。
兩遍文件遍歷法(2-Pass In-Memory Inversion)
此方法在記憶體裡完成索引的建立過程。要求記憶體要足夠大。
第一遍
收集一些全域性的統計資訊。包括文件集合包含的文件個數N,文件集合內所包含的不同單詞個數M,每個單詞在多少個文件中出現過的資訊DF。
將所有單詞對應的DF值全部相加,就可以知道建立最終索引所需的記憶體大小是多少。 獲取資訊後,根據統計資訊分配記憶體等資源,同事建立好單詞相對應倒排列表在記憶體中的位置資訊。
第二遍
逐個單詞建立倒排列表資訊。獲得包含某個單詞的每個文件的文件ID,以及這個單詞在文件中的出現次數TF,然後不斷填充第一遍掃描時所分配的記憶體。當第二遍掃描結束的時候,分配的記憶體正好被填充滿,每個單詞用指標所指向的記憶體區域“片段”,其起始位置和終止位置之間的資料就是這個單詞對應的倒排列表。
排序法(Sort-based Inversion)
在建立索引過程中,始終在記憶體中分配固定大小的空間,用來存放詞典資訊和索引的中間結果,當分配的空間被消耗光的時候,把中間結果寫入磁碟,清空記憶體裡中間結果所佔空間,以用做下一輪存放索引中間結果的儲存區。參考下圖:
上圖是排序法建立索引中間結果的示意圖。建立過程:
1 2 3 4 5 6 7 |
讀入文件後,對文件進行編號,賦予唯一的文件ID,並對文件內容解析; 將單詞對映為單詞ID; 建立(單詞ID、文件ID、單詞頻率)三元組; 將三元組追加進中間結果儲存區末尾; 然後依次序處理下一個文件; 當分配的記憶體定額被佔滿時,則對中間結果進行排序(根據單詞ID->文件ID的排序原則); 將排好序的三元組寫入磁碟檔案中。 |
注:在排序法建立索引的過程中,詞典是一直儲存在記憶體中的,由於分配記憶體是固定大小,漸漸地詞典佔用記憶體越來越大,那麼,越往後,可用來儲存三元組的空間越來越少。
建立好索引後,需要合併。
合併時,系統為每個中間結果檔案在記憶體中開闢一個資料緩衝區,用來存放檔案的部分資料。將不同緩衝區中包含的同一個單詞ID的三元組進行合併,如果某個單詞ID的所有三元組全部合併完成,說明這個單詞的倒排列表已經構建完成,則將其寫入最終索引中,同事將各個緩衝區中對應這個單詞ID的三元組內容清空。緩衝區繼續從中間結果檔案讀取後續的三元組進行下一輪合併。當所有中間結果檔案都依次被讀入緩衝區,併合並完成後,形成最終的索引檔案。
歸併法(Merge-based Inversion)
歸併法與排序法類似,不同的是,每次將記憶體中資料寫入磁碟時,包括詞典在內的所有中間結果都被寫入磁碟,這樣記憶體所有內容都可以被清空,後續建立索引可以使用全部的定額記憶體。歸併法的示意圖如下所示:
與排序法的差異:
1、排序法在記憶體中存放的是詞典資訊和三元組資料,詞典和三元組資料並沒有直接的聯絡,詞典只是為了將單詞對映為單詞ID。歸併法則是在記憶體中建立一個完整的記憶體索引結構,是最終文章索引的一部分。
2、在將中間結果寫入磁碟臨時檔案時,歸併法將這個記憶體的倒排索引寫入臨時檔案,隨後徹底清空所佔記憶體。而排序法只是將三元組資料排序後寫入磁碟臨時檔案,詞典作為一個對映表一直儲存在記憶體中。
3、合併時,排序法是對同一單詞的三元組依次進行合併;歸併法的臨時檔案則是每個單詞對應的部分倒排列表,所以在合併時針對每個單詞的倒排列表進行合併,形成這個單詞的最終倒排列表。
動態索引
在真實環境中,搜尋引擎需要處理的文件集合內有些文件可能被刪除或者內容被修改。如果要在內容被刪除或修改之後馬上在搜尋結果中體現出來,動態索引可以實現這種實時性需求。動態索引有三個關鍵的索引結構:倒排索引、臨時索引和已刪除文件列表。
臨時索引:在記憶體中實時建立的倒排索引,當有新文件進入系統時,實時解析文件並將其追加進這個臨時索引結構中。
已刪除列表:儲存已被刪除的文件的相應文件ID,形成一個文件ID列表。當文件被修改時,可以認為先刪除舊文件,然後向系統增加一篇新文件,通過這種間接方式實現對內容更改的支援。
當系統發現有新文件進入時,立即將其加入臨時索引中。有新文件被刪除時,將其加入刪除文件佇列。文件被更改時,則將原先文件放入刪除佇列,解析更改後的文件內容,並將其加入臨時索引。這樣就可以滿足實時性的要求。
在處理使用者的查詢請求時,搜尋引擎同時從倒排索引和臨時索引中讀取使用者查詢單詞的倒排列表,找到包含使用者查詢的文件集合,並對兩個結果進行合併,之後利用刪除文件列表進行過濾,將搜尋結果中那些已經被刪除的文件從結果中過濾,形成最終的搜尋結果,並返回給使用者。
索引更新策略
動態索引可以滿足實時搜尋的需求,但是隨著加入文件越來越多,臨時索引消耗的記憶體也會隨之增加。因此要考慮將臨時索引的內容更新到磁碟索引中,以釋放記憶體空間來容納後續的文件,此時就需要考慮合理有效的索引更新策略。
完全重建策略(Complete Re-Build)
對所有文件重新建立索引。新索引建立完成後,老的索引被遺棄釋放,之後對使用者查詢的響應完全由新的索引負責。在重建過程中,記憶體中仍然需要維護老的索引對使用者的查詢做出響應。如圖所示
再合併策略(Re-Merge)
有新文件進入搜尋系統時,搜尋系統在記憶體維護臨時倒排索引來記錄其資訊,當新增文件達到一定數量,或者指定大小的記憶體被消耗完,則把臨時索引和老文件的倒排索引進行合併,以生成新的索引。過程如下圖所示:
更新步驟:
1、當新增文件進入系統,解析文件,之後更新記憶體中維護的臨時索引,文件中出現的每個單詞,在其倒排列表末尾追加倒排列表項,這個臨時索引可稱為增量索引
2、一旦增量索引將指定的記憶體消耗光,增量索引和老的倒排索引內容需要進行合併。
高效的原因:在對老的倒排索引進行遍歷時,因為已經按照索引單詞的詞典序由低到高排好順序,所以可以順序讀取檔案內容,減少磁碟尋道時間。
缺點:因為要生成新的倒排索引檔案,所以老索引中的倒排列表沒發生變化也需要讀出來並寫入新索引中。增加了I/O的消耗。
原地更新策略(In-Place)
原地更新策略的出發點是為了解決再合併策略的缺點。
在索引合併時,並不生成新的索引檔案,而是直接在原先老的索引檔案裡進行追加操作,將增量索引裡單詞的倒排列表項追加到老索引相應位置的末尾,這樣就可達到上述目標,即只更新增量索引裡出現的單詞相關資訊,其他單詞相關資訊不變動。
為了能夠支援追加操作,原地更新策略在初始建立的索引中,會在每個單詞的倒排列表末尾預留出一定的磁碟空間,這樣,在進行索引合併時,可以將增量索引追加到預留空間中。如下圖:
實驗資料證明,原地更新策略的索引更新效率比再合併策略低,原因: 1、由於需要做快速遷移,此策略需要對磁碟可用空間進行維護和管理,成本非常高。 2、做資料遷移時,某些單詞及其對應倒排列表會從老索引中移出,破壞了單詞連續性,因此需要維護一個單詞到其倒排檔案相應位置的對映表。降低了磁碟讀取速度及消耗大量記憶體(儲存對映資訊)。
混合策略(Hybrid)
將單詞根據其不同性質進行分類,不同類別的單詞,對其索引採取不同的索引更新策略。常見做法:根據單詞的倒排列表長度進行區分,因為有些單詞經常在不同文件中出現,所以其對應的倒排列表較長,而有些單詞很少見,則其倒排列表就較短。根據這一性質將單詞劃分為長倒排列表單詞和短倒排列表單詞。長倒排列表單詞采取原地更新策略,而短倒排列表單詞則採取再合併策略。
因為長倒排列表單詞的讀/寫開銷明顯比短倒排列表單詞大很多,所以採用原地更新策略能節省磁碟讀/寫次數。而大量短倒排列表單詞讀/寫開銷相對而言不算太大,所以利用再合併策略來處理,則其順序讀/寫優勢也能被充分利用。
查詢處理
建立好索引之後,如何用倒排索引來響應使用者的查詢呢?主要有下面三種查詢處理機制。
一次一文件(Doc at a Time)
以倒排列表中包含的文件為單位,每次將其中某個文件與查詢的最終相似性得分計算完畢,然後開始計算另外一個文件的最終得分,直到所有文件的得分計算完畢為止。然後根據文件得分進行大小排序,輸出得分最高的K個文件作為搜尋結果輸出,即完成了一次使用者查詢的響應。實際實現中,只需在記憶體中維護一個大小為K的優先順序佇列。如下圖所示是一次一文件的計算機制示意圖:
虛線箭頭標出查詢處理計算的前進方向。查詢時,對於文件1而言,因為兩個單詞的倒排列表中都包含這個文件,所以可以根據各自的TF和IDF等引數計算文件和查詢單詞的相似性,之後將兩個分數相加得到文件1和使用者查詢的相似性得分Score1。其他的也是類似計算。最後根據文件得分進行大小排序,輸出得分最高的K隔文件作為搜尋結果輸出。
一次一單詞(Term at a Time)
與一次一文件不同,一次一單詞采取“先橫向再縱向”的方式,首先將某個單詞對應的倒排列表中的每個文件ID都計算一個部分相似性得分,也就是說,在單詞-文件矩陣中首先進行橫向移動,在計算完某個單詞倒排列表中包含的所有文件後,接著計算下一個單詞倒排列表中包含的文件ID,即進行縱向計算,如果發現某個文件ID已經有了得分,則在原先得分基礎上累加。當所有單詞都處理完畢後,每個文件最終的相似性得分計算結束,之後按照大小排序,輸出得分最高的K個文件作為搜尋結果。 下圖是一次一單詞的運算機制。
虛線箭頭指示出了計算的前進方向,為了儲存資料,在記憶體中使用雜湊表來儲存中間結果及最終計算結果。在查詢時,對於文件1,根據TD和IDF等引數計算這個文件對”搜尋引擎“的相似性得分,之後根據文件ID在雜湊表中查詢,並把相似性得分儲存在雜湊表中。依次對其他文件計算後,開始下一個單詞(此處是”技術“)的相似性得分的計算。計算時,對於文件1,計算了相似性得分後,查詢雜湊表,發現文件1以及存在得分,則將雜湊表對應的得分和剛剛計算得到的得分相加作為最終得分,並更新雜湊表1中文件1對應的得分,這樣就得到文件1和使用者查詢最終的相似性得分,類似的計算其他文件,最後將結果排序後輸出得分最高的K個文件作為搜尋結果。
跳躍指標(Skip Pointers)
基本思想:將一個倒排列表資料化整為零,切分為若干個固定大小的資料塊,一個資料塊作為一組,對於每個資料塊,增加元資訊來記錄關於這個塊的一些資訊,這樣即使是面對壓縮後的倒排列表,在進行倒排列表合併的時候也能有兩個好處:
1、無須解壓所有倒排列表項,只解壓部分資料即可
2、無須比較任意兩個文件ID。
下圖是將“Google”這個查詢詞對應的倒排列表加入跳躍指標後的資料結構。
假設對於“Google”這個單詞的倒排列表來說,資料塊的大小為3。然後在每塊資料前加入管理資訊,比如第一塊的管理資訊是«5,Pos1»,5表示塊中第一個文件ID編號,Pos1是跳躍指標,指向第2塊的起始位置。假設要在單詞“Google”壓縮後的倒排列表裡查詢文件ID為7的文件。首先,對倒排列表前兩個數值進行資料解壓縮,讀取第一組的跳躍指標資料,發現其值為,其中Pos1指出了第2組的跳躍指標在倒排列表中的起始位置,於是可以解壓縮Pos1位置處連續兩個數值,得到。5和13是兩組資料中最小的文件ID(即每組資料的第一個文件ID),我們要找的是7,那麼如果7號文件包含在單詞”Google“的倒排列表中的話,就一定會出現在第一組,否則說明倒排列表中不包含這個文件。解壓第1組資料後,根據最小文件編號逆向恢復其原始的文件編號,此處的原始文件ID是:5+2=7,與我們要找的文件ID相同,說明7號文件在單詞”Google“的倒排列表中,於是可以結束這次查詢。
從上面的查詢過程可知,在查詢資料時,只需要對其中一個資料塊進行解壓縮和文件編號查詢即可獲得結果,而不必解壓所有資料,很明顯加快查詢速度,並節省記憶體空間。
缺點:增加指標比較操作的次數。
實踐表明:假設倒排列表的長度為L(即包含L個文件ID),使用根號L作為塊大小,則效果較好。
多欄位索引
即對文件的多個欄位進行索引。 實現多欄位索引的方式:多索引方式、倒排列表方式和擴充套件列表方式。
多索引方式
針對每個不同的欄位,分別建立一個索引,當使用者指定某個欄位作為搜尋範圍時,可以從相應的索引裡提取結果。當使用者沒有指定特定欄位時,搜尋引擎會對所有欄位都進行查詢併合並多個欄位的相關性得分,這樣效率較低。多索引方式示意圖如下:
倒排列表方式
將欄位資訊儲存在某個關鍵詞對應的倒排列表內,在倒排列表中每個文件索引項資訊的末尾追加欄位資訊,這樣在讀出使用者查詢關鍵詞的倒排列表的同時,就可以根據欄位資訊,判斷關鍵詞是否在某個欄位出現,以此來進行過濾。倒排列表方式示意圖如下:
擴充套件列表方式
這是用得比較多的支援多欄位索引的方法。為每個欄位建立一個列表,該列表記錄了每個文件這個欄位對應的出現位置資訊。下圖是擴充套件列表的示意圖:
為方便起見,只針對”標題“欄位所建立擴充套件列表。比如第一項,代表對於文件1而言,其標題的位置為從第一個單詞到第4個單詞這個範圍,其他項含義類似。
對於查詢而言,假設使用者在標題欄位搜尋”搜尋引擎“,通過倒排列表可以知道文件1、3、4包含這個查詢詞,接下來需要判斷這些文件是否在標題欄位中出現過查詢詞?對於文件1,”搜尋引擎“這個查詢詞的出現位置是6和10。而通過對應的標題擴充套件列表可知,文件1的標題範圍是1到4,說明文件1的標題內不包含查詢詞,即文件1不滿足要求。對於文件3,”搜尋引擎出現的位置是2、8、15,對應的標題擴充套件列表中,標題出現範圍為1到3,說明在位置2出現的這個查詢詞是在標題範圍內的,即滿足要求,可以作為搜尋結果輸出。文件4也是類似的處理。
短語查詢
短語查詢的本質是如何在索引中維護單詞之間的順序關係或者位置資訊。較常見的支援短語查詢技術包括:位置資訊索引、雙詞索引和短語索引。也可將三者結合使用。
位置資訊索引(Position Index)
在索引中記錄單詞位置資訊,可以很方便地支援短語查詢。但是其付出的儲存和計算代價很高。示意圖如下:
的含義是,5文件包含“愛情“這個單詞,且這個單詞在文件中出現2次,其對應的位置為3和7,其他的含義與此相同。
查詢時,通過倒排列表可知,文件5和文件9同時包含兩個查詢詞,為了判斷在這兩個文件中,使用者查詢是否以短語的形式存在,還要判斷位置資訊。”愛情“這個單詞在5號文件的出現位置是3和7,而”買賣“在5號文件的出現位置是4,可以知道5號文件的位置3和位置4分別對應單詞”愛情“和”買賣“,即兩者是一個短語形式,而根據同樣的分析可知9號文件不是短語,所以5號文件會被作為搜尋結果返回。
雙詞索引(Nextword Index)
統計資料表明,二詞短語在短語中所佔比例最大,因此針對二詞短語提供快速查詢,能解決短語查詢的問題。但是這樣做的話倒排列表個數會發生爆炸性增長。雙詞索引的資料結構如下圖:
由圖可知,記憶體中包含兩個詞典,分別是”首詞“和”下詞“詞典,”首詞“詞典有指向”下詞“詞典某個位置的指標,”下詞“詞典儲存了緊跟在”首詞“詞典的常用短語的第2個單詞,”下詞“詞典的指標指向包含這個短語的倒排列表。比如”我的“這個短語,其倒排列表包含文件5和7,”的父親“這個短語,其倒排列表包含文件5,其餘詞典也是類似的含義。
對於查詢,使用者輸入”我的父親“進行查詢,搜尋引擎將其進行分詞得到”我的“和”的父親“兩個短語,然後分別查詢詞典資訊,發現包含”我的“這個短語的是文件5和文件7,而包含”的父親“這個短語的有文件5。檢視其對應的出現位置,可以知道文件5是符合條件的搜尋結果,這樣就完成了對短語查詢的支援。
雙詞索引會使得索引急劇增大,一般實現並非對所有單詞都建立雙詞索引,而是隻對計算代價高的短語建立雙詞索引。
短語索引(Phrase Index)
直接在詞典中加入多次短語並維護短語的倒排列表。缺點就是不可能事先將所有短語都建好索引。通用做法就是挖掘出熱門短語。下圖是加入短語索引後的整體索引結構:
對於查詢,當搜尋引擎接收到使用者查詢後,現在短語索引裡查詢,如果找到,則計算後返回給使用者搜尋結果,否則仍然利用常規索引進行查詢處理。
混合方法
將三者結合起來,接收到使用者查詢後,系統首先在短語索引中查詢,如果找到則返回結果,否則在雙詞索引中查詢,如果找到則返回結果,否則從常規索引中對短語進行處理,充分發揮各自的優勢。3種方式的混合索引結構如下圖所示:
短語查詢用來對熱門短語和高頻短語進行索引,雙詞索引對包含停用詞等高代價短語進行索引。
對於查詢,系統首先在短語索引中查詢,如果找到則返回結果,否則在雙詞索引中查詢,如果找到則返回結果,否則從常規索引中對短語進行處理,這樣就充分發揮各自的優勢。
分散式索引(Parallel Indexing)
當搜尋引擎需要處理的文件集合太多的時候,就需要考慮分散式解決方案。每臺機器維護整個索引的一部分,有多臺機器協作來完成索引的建立和對查詢的響應。
按文件劃分(Document Paritioning)
將整個文件集合切割成若干個子集合,而每臺機器負責對某個文件子集合建立索引,並響應查詢請求。按文件劃分示意圖如下:
工作原理:查詢分發伺服器接收到使用者查詢請求後,將查詢廣播給所有索引伺服器。每個索引伺服器負責部分文件子集合的索引維護和查詢響應。當索引伺服器接收到使用者查詢後,計算相關文件,並將得分最高的K個文件送返查詢分發伺服器。查詢分發伺服器綜合各個索引伺服器的搜尋結果後,合併搜尋結果,將得分最高的m個文件作為最終搜尋結果返回給使用者。
按單詞劃分(Term Paritioning)
每個索引伺服器負責詞典中部分單詞的倒排列表的建立和維護。按單詞劃分示意圖如下:
工作原理:一次一個單詞。假設查詢包含A、B、C三個單詞,查詢伺服器接收到查詢後,將查詢轉發到包含單詞A倒排列表的索引伺服器節點1,索引伺服器節點1提取A的倒排列表,並累計計算搜尋結果的中間的分,然後將查詢和中間結果傳遞給包含單詞B倒排列表的索引伺服器節點,索引伺服器節點2也是類似處理,並繼續到索引伺服器節點3。然後將最終結果返回給查詢分發伺服器,查詢分發伺服器計算得分最高的K個文件作為搜尋結果輸出。
兩種方案比較
按文件比較常用,按單詞劃分只在特殊應用場合才使用。 按單詞劃分的不足:
可擴充套件性
搜尋引擎處理的文件是經常變動的。如果按文件來對索引劃分,只需要增加索引伺服器,操作起來很方便。但如果是按單詞進行索引劃分,則對幾乎所有的索引伺服器都有直接影響,因為新增文件可能包含所有詞典單詞,即需要對每個單詞的倒排列表進行更新,實現起來相對複雜。
負載均衡
常用單詞的倒排列表非常龐大,可能會達到幾十M大小。如果按文件劃分,這種單詞的倒排列表會比較均勻地分佈在不同的索引伺服器上,而按單詞進行索引劃分,某個常見單詞的倒排列表全部內容都由一臺索引伺服器維護。如果該單詞同時是一個流行詞彙,那麼該伺服器會成為負載過大的效能瓶頸。
容錯性
假設某臺伺服器出現故障。如果按文件進行劃分,那麼隻影響部分文件子集合,其他索引伺服器仍然能響應。但如果按單詞進行劃分,若索引伺服器發生故障,則某些單詞的倒排列表無法訪問,使用者查詢這些單詞的時候,會發現沒有搜尋結果,直接影響使用者體驗。
對查詢處理方式的支援
按單詞進行索引一次只能查詢一個單詞,而按文件劃分的不受此限制。
總結
通過了解搜尋引擎使用的資料結構和演算法,對其工作原理有了進一步的認識。對於sphinx來說,線上上環境可以考慮增量索引和一次全量索引結合達到實時性的效果。
由於底層基礎比較差,花了大半個月重複讀了幾遍才能弄懂第三章講的內容,真正體會到資料結構和演算法真的很重要。雖然日常工作很少會直接用到資料結構和演算法,但是知道了常用的資料結構和演算法之後,在遇到問題時就會有更多解決方案的思路,厚積薄發。
到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式