最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

pythonxapian存儲結(jié)構(gòu)

來源:懂視網(wǎng) 責編:小采 時間:2020-11-27 14:27:20
文檔

pythonxapian存儲結(jié)構(gòu)

pythonxapian存儲結(jié)構(gòu):在項目中為了支持搜索服務(wù),我們使用xapian作為后端的搜索引擎.其因性能良好以及易用受到大家歡迎.下面是基本代碼: import xapian import posixpath def get_db_path(): XAPIAN_ROOT = '/tmp/' xapian_user_datab
推薦度:
導(dǎo)讀pythonxapian存儲結(jié)構(gòu):在項目中為了支持搜索服務(wù),我們使用xapian作為后端的搜索引擎.其因性能良好以及易用受到大家歡迎.下面是基本代碼: import xapian import posixpath def get_db_path(): XAPIAN_ROOT = '/tmp/' xapian_user_datab

在項目中為了支持搜索服務(wù),我們使用xapian作為后端的搜索引擎.其因性能良好以及易用受到大家歡迎.下面是基本代碼:

import xapian
import posixpath
def get_db_path():
 XAPIAN_ROOT = '/tmp/'
 xapian_user_database_path = posixpath.join(XAPIAN_ROOT, u'user_index')
 return xapian_user_database_path
def add_document(database, words):
 doc = xapian.Document()
 for w in words:
 doc.add_term(w)
 database.add_document(doc)
def build_index():
 user_database = xapian.WritableDatabase(get_db_path(), xapian.DB_CREATE_OR_OPEN)
 words = ['a', 'b', 'c']
 add_document(user_database, words)
def search(words, offset=0, length=10):
 user_database = xapian.Database(get_db_path())
 enquire = xapian.Enquire(user_database)
 query = xapian.Query(xapian.Query.OP_AND, words)
 enquire.set_query(query)
 return enquire.get_mset(int(offset), int(length))
def _show_q_results(matches):
 print '%i results found.' % matches.get_matches_estimated()
 print 'Results 1 - %i:' % matches.size()
 for match in matches:
 print '%i: %i%% docid=%i [%s]' % (match.rank + 1,
 match.percent,
 match.docid,
 match.document.get_data()
 )
if __name__ == '__main__':
 #index 
 build_index()
 
 #search
 _show_q_results(search(['a','b']))

雖然使用起來很簡單,但是我一直對于他的存儲引擎有些好奇,所以看了一下最新的存儲引擎brass的實現(xiàn).下面是整個數(shù)據(jù)目錄的層次結(jié)構(gòu):
/tmp/user_index
flintlock
iamchert
postlist.baseA
postlist.baseB
postlist.DB //存儲所有term 到 docid的映射.
record.baseA
record.baseB
record.DB //存儲所有docid 到 相應(yīng)的數(shù)據(jù)的映射
termlist.baseA
termlist.baseB
termlist.DB //存儲所有docid 到 相應(yīng)的 term的映射.

brass存儲引擎采用的數(shù)據(jù)結(jié)構(gòu)是BTree.所以上面每個*.DB都是存儲一個BTree的.*.baseA/B則是存儲相應(yīng)的.DB的meta信息.包括這個大的數(shù)據(jù)文件有哪些數(shù)據(jù)塊已經(jīng)被使用,哪些空閑的bitmap,以及版本號等等相關(guān)信息.
BTree在xapian中表示為N Level.每個level對應(yīng)于BTree的一層.并且維護這一層的一個cursor.用于指向當前正在訪問的某一個數(shù)據(jù)塊,以及數(shù)據(jù)塊中的某一個位置.其中每個數(shù)據(jù)塊的數(shù)據(jù)結(jié)構(gòu)如下:

from @brass_table.cc
/* A B-tree comprises (a) a base file, containing essential information (Block
 size, number of the B-tree root block etc), (b) a bitmap, the Nth bit of the
 bitmap being set if the Nth block of the B-tree file is in use, and (c) a
 file DB containing the B-tree proper. The DB file is divided into a sequence
 of equal sized blocks, numbered 0, 1, 2 ... some of which are free, some in
 use. Those in use are arranged in a tree.
 Each block, b, has a structure like this:
 R L M T D o1 o2 o3 ... oN <gap> [item] .. [item] .. [item] ...
 <---------- D ----------> <-M->
 And then,
 R = REVISION(b) is the revision number the B-tree had when the block was
 written into the DB file.
 L = GET_LEVEL(b) is the level of the block, which is the number of levels
 towards the root of the B-tree structure. So leaf blocks
 have level 0 and the one root block has the highest level
 equal to the number of levels in the B-tree.
 M = MAX_FREE(b) is the size of the gap between the end of the directory and
 the first item of data. (It is not necessarily the maximum
 size among the bits of space that are free, but I can't
 think of a better name.)
 T = TOTAL_FREE(b)is the total amount of free space left in b.
 D = DIR_END(b) gives the offset to the end of the directory.
 o1, o2 ... oN are a directory of offsets to the N items held in the block.
 The items are key-tag pairs, and as they occur in the directory are ordered
 by the keys.
 An item has this form:
 I K key x C tag
 <--K-->
 <------I------>
 A long tag presented through the API is split up into C tags small enough to
 be accommodated in the blocks of the B-tree. The key is extended to include
 a counter, x, which runs from 1 to C. The key is preceded by a length, K,
 and the whole item with a length, I, as depicted above.

上面來自于xapian的注釋已經(jīng)很清楚的說明了每個block的數(shù)據(jù)構(gòu)成.除了數(shù)據(jù)元信息,就是由item組成的小的數(shù)據(jù)單元.其中每個小的item包括I(整個數(shù)據(jù)單元的長度),K(數(shù)據(jù)單元key的長度+x(key標示符)),C(表示對應(yīng)的這個key有多少個item組成,因為某一個key對應(yīng)的value太大的話,會進行value切分.所以C就表示總計有多少分.而之前的那個x則表示這個單元是第幾份數(shù)據(jù),這個如果需要讀取這個key的整個大value就可以根據(jù)序號x進行合并.),tag就是我們剛才說的key對應(yīng)的value,只不過xapian把它定義為tag.因為他是一個通用存儲結(jié)構(gòu),所以這樣定義也比較說的通.比如說在一顆BTree的非葉子節(jié)點tag存儲的是下一層數(shù)據(jù)塊的地址.對于葉子節(jié)點來說則存儲相關(guān)的數(shù)據(jù).現(xiàn)在整個樹的存儲結(jié)構(gòu)已經(jīng)清晰的展示出來了.

這里面有一個問題比較有意思的是postlist的存儲,設(shè)想某一個熱點詞包含有很多很多的docid,比如說有100w個.那么當我們進行增量更新的時候,想要把某個docid從這個term刪除掉,那么怎么才能盡快查找到這個docid在哪個數(shù)據(jù)塊中呢?作者采用了term+docid作為BTree的key的方式來解決這個問題.value則是所有的大于這個docid的docid.并且每個塊設(shè)定一個大小.這樣就能讓我們能盡快的定位一個docid在哪個block中,而不用讀取所有的block然后再去查找了.

xapian還支持多個reader,單線程writer的方式進行增量更新.采用的類似數(shù)據(jù)庫中的MVCC的方式,這樣就不會因為更新把讀操作阻塞住了.

目前作者正在開發(fā)replication方式,可以支持增量更新到其他機器.這樣就能做到數(shù)據(jù)可靠(不會應(yīng)為單機磁盤損壞導(dǎo)致數(shù)據(jù)丟失)以及高可用性(單機不可用,應(yīng)用層可以切換到備用機器上)了.

BTW:我這兩天看了xapian devel的郵件列表,雖然沒有提交問題,但是看了作者(Olly Betts)對于每個問題都會給出耐心又詳盡的答復(fù),他人真的是很好.很是佩服.

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

pythonxapian存儲結(jié)構(gòu)

pythonxapian存儲結(jié)構(gòu):在項目中為了支持搜索服務(wù),我們使用xapian作為后端的搜索引擎.其因性能良好以及易用受到大家歡迎.下面是基本代碼: import xapian import posixpath def get_db_path(): XAPIAN_ROOT = '/tmp/' xapian_user_datab
推薦度:
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top