建立索引
目前主流的索引技術有三種:倒排文件、后綴數組和簽名。后綴數組的方法雖然快,但是其維護困難,代價相當高,不適合做引擎的索引。簽名是一種很好的索引方式,但倒排文件的速度和性能已經超過了簽名。倒排文件是一種在各大搜索引擎中被主要使用的索引的方式,並且它也是搜索引擎中一個核心的技術。
5.2.1 倒排文件索引(Inverted File Index)的建立
倒排索引文件是一種面向單詞的索引機制,每個文件都可以用一系列關鍵字來表示。一個典型的倒排索引主要由詞匯表(也叫索引項)和事件表(也叫文件鏈表)兩部分組成。詞匯表是用來存放分詞詞典的,通常稱存放詞匯表的文件為索引文件;事件表是用來存放這個文件中對應詞匯表中詞匯出現的位置和次數的,通常稱存放出現位置的文件為位置文件。
1.倒排文件的建立
(1)順排文件的建立
假設有網頁P1,P2,……,Pn,給每個網頁文件賦予一個編號Pid,給每個關鍵字賦予一個編號keyi,假設key是網頁文件中的一個關鍵字,ni表示該關鍵字在網頁文件中出現的次數,<hit1,hit2,…,hitn>表示該關鍵字在網頁文件中的位置信息。首先將網頁內容切分成一系列關鍵字:Pi={Key1,key2,…,keyn}。建立以下順排文件:
P1={[n1,Key1(hit1,hit2,…,hitn)],…,[nx,keyi(hit1,hit2,…,hitx)] }
P2={[n1,Key1(hit1,hit2,…,hitn)],…,[nn,keyk(hit1,hit2,…,hitn)] }
…………
Pn={[n1,Key1(hit1,hit2,…,hitn)],…,[ny,keyj(hit1,hit2,…,hity)] }
例如,對以下兩段文字進行順排文件操作。
“隨着經濟的發展,人們對生活的品質要求越來越高。特別是在視覺欣賞方面,更是追求精益求精。如何把模糊的圖像變得清晰,把暗淡的色彩變得色彩鮮艷是一個非常值得研究的課題。並且在數字電視、掃描儀、醫療圖像、計算機視覺、衛星監測、航空攝像等方面對圖像的清晰度有着廣泛的需求。目前基於網格和密度的聚類方法已經滲透到各個領域,且得到了令人意想不到的效果。本文是將基於網格和密度的聚類方法運用到模糊圖像中,從而對圖像進行增色處理。”
“數字圖像處理又稱為計算機圖像處理,它是指將圖像信號轉換成數字信號並利用計算機對其進行處理的過程。數字圖像處理最早出現於20世紀50年代,當時的電子計算機已經發展到一定水平,人們開始利用計算機來處理圖形和圖像信息。數字圖像處理作為一門學科大約形成於20世紀60年代初期。早期的圖像處理的目的是改善圖像的質量,它以人為對象,以改善人的視覺效果為目的。”
假設第一段文字是一個網頁P1的全部內容,段首的起始位置為1。第二段文字是第二個網頁P2的全部內容,段首的起始位置為1。
對網頁進行自動分詞,得到關鍵字以及關鍵字在網頁文件中出現的位置信息。順排文件的結果為:
P1={[1,經濟(3)],[1,發展(6)],……,[2,視覺(26,93)],……,[5,圖像(46,88,107,177,182)],……,[1,處理(189)]}
P2={[4,數字(1,29,48,101)],[8,圖像(3,13,21,49,96,103,130,140)],……,[1,視覺(156)],……,[2,目的(135,161)]}
(2)實現倒排文件的原理
順排文件是以網頁來索引關鍵字的,即形式為(網頁→關鍵字),不符合搜索引擎的需要。因此,需進行倒排處理,以關鍵字來索引網頁,即形式為(關鍵字→網頁):
Keyi→{[Pid1,ni1(hit1,hit2,…,hitni1)],…,[Pidn,nin(hit1,hit2,…,hitnin)]}
對以上順排文件中建立的兩個實例網頁P1和P2的順排文件進行倒排,倒排文件的結果為:
經濟→{[P1,1(3)]}
發展→{[P1,1(6)],[P2,1(74)]}
……
視覺→{[P1,2(26,93)],[P2,1(156)]}
……
圖像→{[P1,5(46,88,107,177,182)],[P2,8(3,13,21,49,96,103,130,140)]}
……
綜上所述,倒排文件的實現過程是:先得到順排文件,然后根據順排文件得到倒排文件,從而實現由關鍵字來索引網頁。
(3)倒排文件的優化之一—位圖文件
在實際中,一般索引項並不存儲實際的關鍵字,而存儲它的一個編號值(kid),這樣可以有效節約存儲空間。對於文件鏈表(Posting),只存儲網頁文件編號(Pid)和網頁文件編號加上該關鍵字在文件中出現的位置信息。
其中Pid1,…,Pidn表示包含關鍵字ki的所有網頁文件集合,考慮到文件鏈表進行布爾運算時,速度不是很快,以及使用文件鏈表要消耗大量內存等問題,一般采用位圖(Bitmap)文件來實現倒排索引。Bitmap的優點是布爾運算非常快,直接用對應的bit位作運算就可以了。想要得到同時包含某幾個關鍵字的網頁,那么直接把它們對應的網頁文件位圖向量進行與運算,就可以知道在哪些文件中同時包含了這幾個關鍵字。在文件數目不是很多的情況下,只存儲命中信息,實現了命中信息和非命中信息(比如關鍵字在文件中的位置,關鍵字在文件中出現的頻率等)的分離,可以大大提高索引的效率。
把由網頁文件向量Pi=<key1,key2,…,keyn>構成的“網頁→關鍵字”,轉化成“關鍵字→網頁”。轉換方法是根據網頁文件向量構成“網頁-關鍵字”陣列,如圖5-2所示,並用Bitmap作為存儲結構,形成倒排矩陣A,如圖5-3所示。
倒排矩陣中的Aij元素取值為0,表示網頁Pj中沒有關鍵字ki;倒排矩陣中的Aij元素取值為1,表示網頁Pj中有關鍵字ki。以此可以得到包含某關鍵字的網頁的文件集合,然后根據文件鏈表得到此關鍵字在網頁中的出現位置信息。
![]() |
Bitmap文件實現的倒排矩陣在海量數據環境下是比較稀疏的,必須對它進行壓縮,並且保證在解壓的過程中,速度也比較快,這樣可以大大提高索引的性能,也節省了大量的存儲空間。目前比較成熟的位圖壓縮算法主要有Delta encoding、Variable-length encoding、Gamma codes等。
雖然它們都是比較成熟的算法,但是要么實現起來比較復雜;要么壓縮效率很高,但是解壓的過程要消耗較長的時間,這對於搜索引擎的實時響應要求很高的系統是不適合的。
2.改善倒排文件性能的方法
倒排文件的時間代價主要取決於詞匯表的組織方式,詞匯表文件通常較小且比較固定,對於未登錄詞和數詞可以按字建索引;倒排文件的空間代價主要取決於對事件表的壓縮能力,事件表的壓縮能減少I/O操作,也能提高部分時間性能。詞匯表文件的組織方式通常采用Hash散列表,按字母表順序有序排列,采用Trie樹、B樹等查找樹。事件表的壓縮通常采用Bitmap文件壓縮或差值壓縮(Delta Compression)詞匯表的哈希存儲,根據給定的關鍵字,散列成一個整數,用該整數作為詞匯的訪問地址。
倒排文件的優點是:實現簡單,響應時間快,支持復雜查詢,適合商用搜索引擎。缺點是:建立索引要消耗很大的磁盤、內存空間;當網頁更新后,索引的維護代價也比較大
下面講解一個倒排文件索引的例子—Lucene倒排索引。Lucene是一個高性能的Java全文檢索工具包,它使用的是倒排文件索引結構。該結構及相應的生成算法如下。
假設有3篇文章:
文章1的內容為:I was a student, i came from chengdu.
文章2的內容為:My father is a teacher, and i am a student.
文章3的內容為:Chengdu is my hometown. my father’s hometown is wuhan.
Lucene是基於關鍵字索引和查詢的。首先取得這3篇文章的關鍵字,通常需要如下處理措施(在Lucene中以下措施由Analyzer類完成):
1)需要把3篇文章的內容切分成一個個單詞,作為索引關鍵字的候選集。英文中單詞與單詞之間有空格,分詞比較好處理,但中文字與字之間沒有空隔,是連在一起的,所以中文分詞處理要麻煩。
2)需要將文章中分離出來的沒有實際意義的單詞過濾掉。比如a、from、and,中文中的“的”、“也”、“啊”等通常無具體含義的詞可以去掉。還要過濾掉標點符號。
3)單詞需要統一大小寫。
4)查找與當前關鍵字相關聯的其他關鍵字,即統一單詞不同的時態。如“came”、“coming”統一成“come”,再進行查找。
經過上面處理后,3篇文章的所有關鍵字為:
文章1:[i] [am] [student] [i] [come] [chengdu]
文章2:[my] [father] [is] [teacher] [i] [am] [student]
文章3:[chengdu] [is] [my] [hometown] [my] [father] [hometown] [is] [wuhan]
有了關鍵字后,就可以建立倒排索引了。上面的對應關系是順排的,即“文章號→關鍵字”,倒排處理為“關鍵字→文章號”。文章1、2、3經過倒排后變成如表5-1所示。
表5-1 倒排文件
關 鍵 字 |
文 章 號 |
i |
1,2 |
am |
1,2 |
student |
1,2 |
come |
1 |
chengdu |
1,3 |
my |
2,3 |
father |
2,3 |
is |
2,3 |
teacher |
2 |
hometown |
3 |
wuhan |
3 |
加上“出現頻率”和“出現位置”信息后,索引結構變為如表5-2所示。
表5-2 索引結構
關 鍵 字 |
文章號[出現頻率] |
出 現 位 置 |
i |
1[2],2[1] |
[1,4,5] |
am |
1[1],2[1] |
[2,6] |
student |
1[1],2[1] |
[3,7] |
come |
1[1] |
[5] |
chengdu |
1[1],3[1] |
[6,1] |
my |
2[1],3[2] |
[1,3,5] |
father |
2[1],3[1] |
[2, 6] |
is |
2[1],3[2] |
[3,2,8] |
teacher |
2[1] |
[4] |
hometown |
3[2] |
[4,7] |
wuhan |
3[1] |
[9] |
以my這行為例來說明一下該結構。my在文章2中出現了1次,文章3中出現了2次,它的出現位置為“1,3,5”,結合文章號和出現頻率來分析,文章2中出現了1次,那么“1”就表示my在文章2中出現的一個位置,文章3中出現了2次,剩下的“3,5”就表示my是文章3中第3個和第5個關鍵字。
以上便是Lucene索引結構中最核心的部分。關鍵字是按字符順序排列的(Lucene沒有使用B樹結構),因此Lucene可以用二元搜索算法快速定位關鍵字。
實現時Lucene將上面三列分別作為詞典文件(Term Dictionary)、頻率文件(Frequencies Dictionary)、位置文件(Positions Dictionary)保存(將事件表分為兩個文件)。其中詞典文件不僅保存有每個關鍵字,還保留了指向頻率文件和位置文件的指針,通過指針可以找到該關鍵字的頻率信息和位置信息。
Lucene中使用了field的概念,用於表達信息所在位置(如標題中、文章中、url中),在建索引中,該field信息也記錄在詞典文件中,每個關鍵字都有一個field信息(因為每個關鍵字一定屬於一個或多個field)。
為了減小索引文件的大小,Lucene對索引還使用了壓縮技術。首先,對詞典文件中的關鍵字進行了壓縮,關鍵字壓縮為<前綴長度,后綴>。例如:當前詞為“馬來西亞語”,上一個詞為“馬來西亞”,那么“馬來西亞語”壓縮為<4,語>。其次大量用到的是對數字的壓縮,數字只保存與上一個值的差值(這樣可以減小數字的長度,進而減少保存該數字需要的字節數)。例如,當前文章號是14569(不壓縮要用3個字節保存),上一文章號是145704,壓縮后保存5(只用一個字節)。