搜索引擎--------倒排表數據結構、通配符查詢、拼寫糾正詳解

目錄:算法

  • Dictionary Data Structure  詞典數據結構
  • Wild-Card Query  通配符查詢
  • Spelling Correction  拼寫糾正

 


 
搜索引擎裏的 dictionary data一般存儲着這些信息:
  • 索引詞term vocabulary)。
  • 文檔頻率document frequency,即這個詞在多少個文檔裏出現)。
  • 指向倒排表的指針pointers to each postings list )。
那麼,他是怎樣的一個數據結構呢?
 
 
一種很是 naive的詞典結構就是:
其中,term的類型是char[20],佔20bytes,document frequency類型int,佔4-8 bytes,pointer指針佔4-8 bytes。
這種數組的存儲方式會有兩個問題:
空間上:  How do we store a dictionary in memory efficiently?
時間上:  How do we quickly look up elements at query time?
 
固然,比較好的數據結構是:
1,Hashtables。2,Trees。
(一些搜索引擎用的是Hashtables,一些用的是trees。)
其實,具體判斷該選擇什麼樣的數據結構,主要從如下三點來衡量:
1,數據是否是持續增加的?
2,訪問查找是否是很頻繁?
3,詞典的規模是否是很大?
 
具體來看看Hashtables和Trees。
若是用的是 Hashtables,那麼每個索引詞都會被一個hash函數轉換成一個整數。
優勢:
查找起來十分迅速,時間是O(1)。
缺點:
若是兩個詞相差十分的小,不容易發現。好比說  judgment/ judgement 。
沒法實現前綴查詢。即查詢全部給點前綴的詞。
若是詞典是持續增加的,須要時不時的對原來的hashtables從新進行hash計算,這個代價是很大的。
Example:
 
 
若是數據結構是樹的話。最簡單的就是二叉樹了。
樹能夠支持前綴查找。搜索速度略低於哈希表方式,時間是O(logM),其中M是詞彙表的大小,即全部詞彙的數目。
O(logM)僅僅對平衡樹成立。可是使二叉樹保持平衡的開銷很大。
如何解決保持平衡的開銷問題呢?
B-樹!!!
首先看B-樹的定義是這樣子的: B-樹是一種平衡的多路查找樹。

一棵m 階的B-樹知足下列特性的m 叉樹:
數組

  • 樹中每一個結點至多有m 棵子樹;

 

  • 若根結點不是葉子結點,則至少有兩棵子樹;
  • 除根結點以外的全部非終端結點至少有[m/2] 棵子樹;
  • 全部的非終端結點中包含如下信息數據:(n,A0,K1,A1,K2,…,Kn,An)。其中:Ki(i=1,2,…,n)爲關鍵碼,且Ki<Ki+1,Ai 爲指向子樹根結點的指針(i=0,1,…,n),且指針Ai-1 所指子樹中全部結點的關鍵碼均小於Ki (i=1,2,…,n),An 所指子樹中全部結點的關鍵碼均大於Kn。n爲關鍵碼的個數
  • 全部的葉子結點都出如今同一層次上,而且不帶信息(能夠看做是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點的指針爲空)。

這樣講起來或許比較枯燥難懂,看這張圖就行了:數據結構

樹的優勢就是能夠解決前綴查找的問題了。函數

缺點是速度比哈希慢點,是O(logM)而且要求是平衡的,從新平衡一棵樹的代價大。(雖然B-樹減輕了這種代價)post

 


 

 

Wildcard queries,通配符查詢。

好比查詢語句 mon*:找出全部以mon開頭的單詞。若是採用樹(或者B-樹)結構詞典,咱們能夠很容易的解決,只須要查詢範圍在mon ≤ w < moo的全部單詞就ok了。ui

可是查詢語句 *mon:找出全部以mon結尾的單詞就比較困難了。其中一種辦法就是咱們增長一個額外的B-樹來存儲全部單詞,以從後向前的順序,而後在這個樹上查詢範圍在nom ≤ w < non的全部單詞。搜索引擎

但是如何處理通配符在單詞中間的查詢呢?google

好比query是co*tion的話。咱們固然能夠分別在B-樹查詢到co*和*tion的全部單詞而後合併這些單詞,可是這樣開銷太大了。spa

解決辦法就是:輪排索引(Permuterm Index)咱們把query的通配符轉換到結尾處。指針

設置一個標誌$表示單詞的結尾。

以hello舉例,hello能夠被轉換成hello$, ello$h, llo$he, lo$hel, o$hell。$表明中hello的結束。如今,查詢X等於查詢X$,查詢X*等於查詢X*$,查詢*X等於查詢X$*,查詢X*Y等於查詢Y$X*。對於hel*o來講,X等於hel,Y等於o。

既然咱們已經把通配符都弄到了單詞尾部,如今咱們又能夠經過B-樹像之前那樣查詢拉。

以上,咱們已經完成了對query的轉換,那麼那些存儲的索引的詞要怎麼處理才能配合這種query查詢呢?

咱們對索引來創建索引!!

Bigram indexes。就是兩兩個字母來索引。

舉例來講,一個文本是「April is the cruelest month」,分別成Bigram indexes就是「$a,ap,pr,ri,il,l$,$i,is,s$,$t,th,he,e$,$c,cr,ru,ue,el,le,es,st,t$, $m,mo,on,nt,h$」,其中$ 表明着單詞邊界的符號。

那麼如何對索引創建索引??

維護第二個倒排表,倒排表的索引詞是Bigram indexes,posting list的值就是與之匹配的dictionary terms。

像這樣:

 

好了!目前爲止,咱們既對query進行了處理,也對terms進行了處理。

因此如今若是咱們要查詢 mon*,query會被分解成 $m AND mo AND on ,而後從上圖中的倒排表作兩個AND能夠獲得匹配的terms了!!

可是,咱們會發現 $m AND mo AND on 也會匹配到單詞moon,而moon不符合mon*的格式,這是他的一個缺點。咱們必需要過濾掉這些詞。

另外,一條查詢語句每每至關多的布爾查詢,這個開銷也挺大的。

 


 

Spelling correction,拼寫校訂。

咱們google一下 Alanis Morisett ,獲得結果如圖:

對了,就是這個提示,您找的是否是:xxxxxx。

在搜索引擎中,須要有一個能夠查詢到全部正確單詞的詞典。

給定一個詞典和一個query,返回一個和query最接近的words。

怎麼用纔算是最接近??

  • 編輯距離算法。
  • 帶權編輯距離算法。

編輯距離(Edit distance)

給定兩個字符串S1和S2,從S1轉換到S2的最小步驟就是他們的編輯距離。這些步驟包括,Insert(1步), Delete(1步), Replace(1步),copy(0步)

好比說:

dof到dog的編輯距離是1,cat到act的編輯距離是2,cat到dog的編輯距離是3.

算法導論裏關於編輯距離的僞代碼以下:

 

舉例子:算cats到fast的編輯距離~

括號裏圈出來的表示實際應該填的值,其餘的只是用來進行對比,取其中最小的數。

具體到表中的每一格中四個數字的含義就是:

 

從左邊的格子過來表明增長,上邊的格子過來表明刪除,斜上角的格子過來表明替換(此時兩個字符不相等)或複製(此時兩個字符不相等)。

編輯距離就是這樣子。那麼什麼是帶權編輯距離呢?

好比說,咱們打字的時候,m被錯打成n的概率會比m錯打成p的概率更大,因此咱們應該認爲m和n的編輯距離小於m到p的編輯距離。所以將m替換爲n時計算編輯距離應該比將m替換爲p時的編輯距離小。

實現帶權編輯距離,咱們須要一個額外的權值矩陣。

那麼,給定一個查詢詞,咱們是否是得計算這個查詢詞和全部的索引詞之間編輯距離呢?

答案是否認的,由於這樣開銷很大並且慢。

怎麼用減小計算呢??

好比說,若是query是lord:

咱們只取lo,or,rd中有重疊兩次或以上的term,而後合併這些term,以這個爲範圍進行編輯距離的計算。

 


 

若是本文對您有一點點的幫助,請幫忙點個贊,十分感謝!~ =。=

若是您有更好的看法或糾正,歡迎您在下面評論指出。

相關文章
相關標籤/搜索