Xapian:Database

在Xapian1.0之前,是使用quartz作爲database文件格式的,不過自從1.0之後,便改用Flint作爲database的文件格式了。有時候,我們會將database稱爲“索引”,在Xapian中,索引通常比被索引的documents還要多,這表示Xapian做一個信息檢索系統比做一個信息存儲系統更適合。

   Database的存儲結構

Xapian的database是所有用於檢索的信息表的集合,以下的表是必需的:

l         posting list table 保存了被每一個term索引的document,實際上保存的應該是document在database中的Id,此Id是唯一的。

l         record table 保存了每一個document所關聯的data,data不能通過query檢索,只能通過document來獲取。

l         term list table 保存了索引每個document的所有的term。

以下的表是可選的,即當有以下的類型的數據需要被存儲的時候纔會出現(在1.0.1以前,position和value表就算是沒有數據的時候也會被創建,而spelling和synonym表是1.0.2後纔出現的)。

l         position list table 保存了每一個Term出現在每一個document中的位置

l         value table 保存了每一個document的values,values是用作保存、排序或其它作用的。

l         spelling table 保存了拼寫糾正的數據。

l         synonym table 保存術語的字典,例如NBA、C#或C++等。

以上的每一個集合是保存在獨立的文件中,以便允許管理員查看其中的數據。剛剛說了,有一些表不是必需的,例如當您不需要詞組搜索的時候,沒必要存儲任何的postionlist信息。

如果你看過Xapian的database,你會發現以上的每一個表其實是使用了2到3個文件的,如果您正在使用“flint”作爲database的存儲格式,那麼termlist表會被存儲爲以下三個文件“termlist.baseA”、“termlist.baseB”、“termlist.dB”。在這些文件中,其實只有”.db”文件存儲了真實的數據,“.baseA”和“baseB”文件是用作跟蹤如果於“.dB”文件中查找數據。通常只會出現一個“.baseA”文件和一個“.baseB”文件。

在前一篇《利用Xapian構建自己的搜索引擎:簡介》中提到過,Xapian現在的版本默認是使用flint作爲存儲系統,“.dB”文件是以塊的形式來存儲,默認每塊是8K,第一塊是用作信息頭,如果使用UltraEdit等二進制查看工具,會發現所有“.dB”文件的前三個字節都是0x00。因此,當“.dB”中僅有一條數據的時候整個文件也會有16KB時,切莫大驚小怪。

改變“.dB”文件的默認塊大小會導致性能變化,但結果很難說是好是壞,因爲這是跟所承載的硬件平臺與操作系統平臺有關的。一般來說,B樹的分支因子(即每個結點能容納的關鍵字的數量)越大,B樹的查找性能就越強;但由於通常情況下,B樹的結點都是存儲在永久存儲系統(例如硬盤/磁帶)中,每次訪問某個結點都會將整個結點由永久存儲系統讀入到內存中,這是一個博弈的過程:假設一棵數據量很大的B樹,將B樹的分支因子設到很大,這棵B樹會長得很矮,從理論上來說查找性能可能很高。但這樣就帶來了一個弊端,每個結點所佔的內存非常多,如果在一個併發訪問量很大的IR系統中採用這種方式的話所使用的內存必定是非常可觀的。因此在調整“.dB”文件的默認塊大小的時候一定要充分考慮cpu體系和操作系統平臺,以便調整到最佳性能。

原子性修改

Xapian能保證對database的所有修改都是原子性的,這意味着:

l         從一個獨立的進程(或一個獨立的database對象在同一個進程)角度來看,在讀取數據庫的時候,直到修改成功提交,所有對數據庫的修改都是不可見的。

l         Database在硬盤中的狀態始終是保持一致的。

l         如果在修改的過程中系統發生中斷,只要硬件不發生故障(硬盤損壞),就算電源被切斷,database應該總是被還原到有效的狀態。

提交一個修改需要幾次的系統調用,以便使所有緩存的修改能刷新到硬盤上,這樣能確保就算系統在任何時候發生錯誤,database也能處於一致的狀態。當然,這樣相對於說會慢了一點(因爲系統已經準備好往硬盤上寫數據了),因此將幾次的修改組合在一起往硬盤上寫會有一定的性能提升。

多個修改操作可以顯式地組合在一個事務中,如果一個應用程序不顯式地使用事務來保護修改操作,Xapian會將這些修改組合在一個事務中,然後批量進行修改。請注意,Xapian現在暫時還不能跨database進行事務操作。

如果要想迅速地生成非常大的database,請使用“DANGEROUS”關鍵字搜索Xapian的郵件列表,其提供了可以重新編譯Xapian而不採用原子性修改的方法,這功能已經不再整合在xapian的標準版本中了。

Single writer, multiple reader

Xapian實現了“單寫多讀”的模式,這意味着任何時候,同一時刻只允許一個對象可以修改database,但允許多個對象可以讀取database。

在*nix系統下,Xapian使用“lock-files”強制約束來實現此模式,在一個flint database中,每一個Xapian的database目錄包含了一個名爲“flintlock”的文件以作鎖定用途。此文件總在存在於database的目錄裏,當database被打開用作寫入的時候,此文件會被fcntl()方法鎖定。每一個WritableDatabase打開的時候,都會產生一個子進程以便進行鎖定操作。如果某個database寫入器(一般是指WritableDatabase)還沒有機會執行釋放鎖的清除操作便退出了(例如這個WritableDatabase所在的應用程被殺死了),fcntl()產生的鎖會自動被操作系統釋放。

在Microsoft Windows下,使用的是另一種鎖定的技術,此技術不需要產生了子進程來進行鎖定操作,但同理,當寫入器退出時,操作系統依然會自動釋放鎖。熟悉Windows機制的朋友知道,Windows是使用文件句柄來操作文件的,而文件句柄是屬於內核資源的一種,在任何情況下,Windows都能保證應用程序在退出時能釋放所有的資源。

網絡文件系統

Xapian現在可以工作在一個網絡文件系統中,但存在着大量的潛在問題。因此建議在部署前要大量地在特定的網絡中測試。

請注意,Xapian是非常依賴I/O操作的,除非處於一個性能非常優秀的網絡,在一個網絡文件系統中進行操作會相對的慢一點。

Xapian需要可以在database的目錄裏創建一個lock file,在某些網絡文件系統中(例如NFS),這需要一個鎖定的守護進程在運行,也就是上面所提到的子進程。

 

創建database

       說了一堆的理論,下面我們來實戰創建一個database。Xapian裏的所有類都處於Xapian這個命名空間裏,Xapian::Database是所有Database的基類,實際上,它只有一個子類,那就是WritableDatabase。從面向對象的角度來看,這兩個類設計得非常好,Xapian::Database擁有大部分只讀或內存操作的方法,而Xapian::WritableDatabase則擁有事務操作,刷新數據到硬盤等方法。

       有幾種創建Database的方法:

l         Flint 如果你是使用遠程後端(指網絡文件系統),請使用Xapian::Flint::open()方法來創建database。使用此方法你能得到更多的控制,例如創建只讀的database,或創建可寫的database。

l         Auto auto並不是一種database格式,你可以創建一個“database存根”文件,此文件能列出一到多個database的路徑,這些路徑可以作爲Xapian::Database的構造函數的參數,從而被自動檢測是哪種類型的database。還有,如果將一個文件路徑名稱而非目錄名稱作爲參數傳入到Xapian::Database的構造函數中,Xapian::Database會認爲你傳入了一個“database存根”文件;當然,你也可以使用Xapian::Auto::open_stub()來顯式打開一個存根文件。上面說的可能有點繞口,“database存根文件”的格式是每個database一行,例如:

remote localhost:23876
flint /var/spool/xapian/webindex

這下該明白了。

l         Inmemory 還可以創建內存databse,這種類型的database是保存在內存中。請注意,通過Xapian::InMemory::open()返回的類型是WritableDatabase,這意味着這是一個可刷新到硬盤上的database,它最初是爲測試之用,但在建立臨時的小數據庫也可能是有用的。

實際上,創建一個database還有更通用的方法,例如通過將一個database所在的完整目錄作爲一個字符串傳入到Xapian::Database的構造函數中實例化一個對象後,即可得到一個只讀的database。而Xapian::WritableDatabase則複雜一點,除了要傳入database的路徑外,還需要設定如何打開database。有以下幾個參數:

l         Xapian::DB_CREATE_OR_OPEN 打開以便讀寫,如果不存在則創建。

l         Xapian::DB_CREATE 總是創建新的database,如果存在則失敗。

l         Xapian::DB_CREATE_OR_OVERWRITE 如果database存在的話則覆蓋之,如果不存在則創建。

l         Xapian::DB_OPEN 打開以便讀寫,如果不存在則失敗。

成功打開一個datababse是Xapian所有後續操作如檢索,寫入的基礎。你甚至可以將通過add_database()方法則多個database組合在一起訪問;如果想將database刷新到硬盤中,則執行flush()方法則可。最後,如果不想使用database了,將database對象銷燬即可。

小結

在這一章裏,似乎並沒有多少具體的操作,但database是Xapian的存儲系統,在Xapian所有操作的基礎,只有清楚明白了Xapian的存儲方式才能更好更高效地構造自己的搜索引擎。同時,如果您之前並沒有對大型的文件存儲系統有所瞭解的話,這篇文件可以多多少少帶給您一些啓示。在下一章裏,我會繼續介紹Document和Term等Xapian的組成部分。

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