索引

在這個信息爆炸的年代, 信息索引的重要性不言而喻。現在主要的索引結構就是倒排索引,又稱爲記錄文件(posting file),詞彙索引(concordance)。其他的還有簽名文件(signature file), 和 位圖(bitmap)。

倒排索引
倒排索引在結構上分爲,倒排列表(inverted list)和字典, 倒排列表就是記錄一列指針, 每個指針表示了術語所在的文檔的編號,甚至是在文檔中的位置。
而字典就是記錄了術語和倒排列表的對應關係。
舉個例子,cold (2;1,4)表示cold這個詞出現了2次,分別在第1和第4號文檔裏面。
那麼索引有個粒度的問題,上面的例子的索引的粒度是文檔級的, 也可以把索引的粒度細化到單詞級的.
那麼索引列表就是這個形式,cold(2;(1;6,7,10),(4;8)), 這邊可以看出單詞級索引要比文檔級索引佔的空間要大的多.
那麼無論什麼粒度的倒排索引,還是要佔比較大的空間的,索引本身能不能壓縮了?
看這樣一個倒排索引(8;3,5,20,21,23,76,77,78),倒排序列以升序序列存放,這個是壓縮的關鍵。
那麼我們可以通過存儲第一個文檔號,和文檔間的gap來實現壓縮。那麼上面的倒排索引被壓縮成,
(8;3,2,15,1,2,53,1,1), 其實單純的用gap替換文檔號並不能實現壓縮,因爲對於N個文檔的文檔集,仍需要logN位去編碼。
但對於文檔號序列,每個文檔號只會出現一次, 而對於gap的序列,會出現高概率的gap,和低概率的gap。
所以對於文檔號序列我們必須用logN來表示每個文檔號,而對於gap序列就可以對高概率的gap用較短的位,對低概率的gap用較長的位來表示,從而實現了壓縮。
那麼這可以說是個符號方法的壓縮問題,所以這個問題的核心就是文檔間隔大小的概率分佈模型 及相應的編碼方法 的問題。

對於一個有N個文檔的文檔集,那麼gap可能值應該也是N個,如果每個gap平均出現, 即每個gap出現的概率是Pr[x]= 1/N , 根據香農公式理想的編碼長度位-logPr[x], 那麼編碼長度爲-log(1/N)= logN, 這個就是不壓縮的情況,二進制編碼

那麼事實情況,gap不可能是平均概率出現, 往往比較小的gap出現的頻率會比較高, 這個是比較直觀的,那麼我們就可以採用一種重視小值的概率模型,

Pr[x]=2(-x) , 即假設gap出現的概率隨着gap的變大成指數級衰減。
那麼理想的編碼長度就是-log2(-x) = x
對於這樣的概率模型的編碼方法就是簡單的一元編碼 ,把x>=1的整數,編碼爲x-1個1比特連接一個0比特。如3, 編爲110,4就是,1110
這個編碼還是比較簡單易懂的, 他的缺點就是隨着gap的變大,概率可能衰減的太快了。
那麼假設Pr[x]=1/2x2 , 即假設gap出現的概率隨着gap的變大成平方級衰減。
那麼理想的編碼長度就是1+ 2logx
對於這樣的概率模型的編碼方法就是r編碼 , 首先對1+logx進行一元編碼,然後用logx比特長度對x-2logx進行二進制編碼,然後將兩部分編碼拼接。 如9的編碼爲1110 001

 

上面這些概率模型都是主觀假設的,如果能根據實際的情況來建立概率模型,也許會有更好的壓縮效果。
那就來看看全局貝努裏模型
N爲文檔數, n爲對立索引詞數,那麼如果每個索引詞在每個文檔裏都出現的話,倒排文件中的指針數應該是N×n,這個就是指針數的上限。
f爲倒排文件中指針數的實際值,那麼f/N*n表示指針的真實密度,即可以認爲是隨機的一個索引詞在隨即的文檔中出現的概率,這裏假定每個單詞均勻分佈在每個文檔裏。(顯然這個假定是不合理的)
那麼假設文檔中出現一個詞概率p
Pr[x]= (1-p)x-1 p , 間隔爲x表示前x-1個文檔都沒有出現這個詞,第x個文檔出現了
那麼現在這個x的概率模型就是建立在p這個客觀的參數上,稱爲’幾何分佈 ‘。
那麼這個概率模型怎麼編碼了, 當然可以用算術編碼, 但是南加州大學的solomon golomb提出了golomb編碼 ,可以有效的以哈夫曼編碼替代算術編碼。
這個編碼比較複雜,門外漢不明白這個怎麼能想出來的,不過和上面的r編碼思路比較象。
即對於任意的參數b,x可以分爲兩部分,q=(x-1)/b, r = x -qb -1, 那麼對q+1進行一元編碼,對r進行logb長度的哈夫曼編碼。
如取b=6,對9進行編碼,q=1,r=2
q的一元編碼爲10
b=6,所以r的值域爲[0,5]6個數, 對這6個數進行前綴編碼(可以看成哈夫曼編碼)爲00,01,100,101,110,111
所以r的編碼爲100
整個編碼爲10100
至於這個b值怎麼選有個公式可以取算的,就不詳細說了,因爲不知其所以然。總之是p越大就是指針密度越大,那麼b就越小。
從某種意義上來講,golomb的構造方法是計算特定無限概率集合的哈夫曼編碼的單步法(one-step method)
我的理解是哈夫曼樹的構造必須是正對一個有限的概率集合, 對於一個無限的集合就沒辦法構建哈夫曼樹。
因爲這邊我們要壓縮文檔間隔的是一個數字,除以一個參數b,得到的餘數r一定是個有限集合,所以可以採用哈夫曼編碼。

那麼上面談到的都是全局的概率模型,全局貝努裏模型也僅僅比其他全局模型稍好一些。
貝努裏模型的壓縮效果和b的選取有很大關係,因爲b越大哈夫曼編碼需要的位數就越多,對於全局貝努裏模型,b是由全局索引詞的指針密度p算出的。這樣是基於一個假設,就是每個索引詞的指針密度是平均的,都差不多的。
但是實際情況往往不是這樣的,會有高頻詞,低頻詞,這樣拿這個全局的b去進行編碼就效果比較差。
那麼爲了改善這一情況, 就有了局部貝努裏模型
很簡單就是根據每個索引詞實際的指針密度來計算局部的b值,那麼這樣就可以高詞頻的用較小b值編碼,低詞頻用較大的b值編碼,相對比較合理了。
在TREC文檔集合中,對於‘hapax legomena’僅出現一次,那麼就用b=50000編碼,長度是20bit左右。對於在10%的文檔中都出現的常用詞,用b=7進行編碼,那麼文檔間隔1,只需要3bit編碼。
那麼如果採用之前的全局貝努裏模型的話,全局最優b=2036, 那麼文檔間隔1也要11bit去編碼。
由於對於不同的索引詞要用不同的b值,所以要額外的爲每個索引詞去存儲指針密度f,用來算出b,不過這個開銷很小。
對於局部貝努裏模型,沒有考慮到詞的成簇性cluster,所以又有‘有偏貝努裏模型’,就不具體講了。

倒排索引基本差不多了,在大概瞭解一下簽名文件(signature file), 和 位圖(bitmap)兩種索引方法,這兩種方法基本已經屬於被淘汰的技術。
簽名文件
顧名思義,就是文檔的一個簽名(signature), 或稱爲‘描述符’(discriptor). 其實就是一個比特串,從某種程度上表示了文檔的內容。
這個簽名怎麼生成了, 舉個例子,
要爲文檔建立一個16bit的簽名,那麼首先爲文檔中的每個索引詞建立個16bit的簽名。
索引詞的16bit的簽名很容易建,找3個不同的hash函數在1~16中算出3個hash值,然後把16bit中這3個hash值的位置置1(這兒有可能會衝突,不同的hash函數算出同樣的值)
然後把所有索引詞的16bit的簽名求’或‘,就得到整個文檔的簽名。這個簽名索引必須足夠的長,纔能有比較好的效果。
這種索引其實只能查出某個索引詞是不是不在該文檔中出現,而沒辦法確定一個詞一定出現在一個文檔中, 需要做錯配的檢查, 這個效率就低了。
位片(bitslicing)簽名文件
這個其實很容易理解,如果你時按文檔簽名來存儲這個簽名文件, 比如你要查哪些文檔中包含cold這個詞,你必須讀出所有的文檔的簽名文件,一個一個去判斷。
這樣你要從磁盤上讀出所有文檔簽名索引,比較低效。
那麼換個思路,我們想象着上面那個文檔簽名的簽名文件是個矩陣,每行代表了這個文檔的簽名,一般的就是這麼一行行的讀出所有索引。
我們現在按這個列去存儲,一列就是一個位片,代表了所有文件在這個bit上的情況,按位片去存儲的好處是什麼了?
比如cold這個詞hash得到1,11,14這3個hash值,那麼要找那些文檔裏包含cold這個詞,我們只需要讀出1,11,14這3個位片數據進行合取,就可以知道那些文檔可能包含cold。
這樣就不用讀出所有的索引文件, 比較高效的方法。

位圖
這是個十分簡單的索引結構,就是爲字典中每個索引詞建個和文檔總數等長bit串,索引詞出現在這個文檔中, 那該文檔的bit位置1,否則置0。可想而知,這個索引非常耗空間的。

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