使用python和xapian構建高速檢索引擎

pythontab發表於2014-01-17

首先弄明白幾個概念:Documents 、terms and posting在資訊檢索(IR)中,我們企圖要獲取的項稱之“document”,每一個document是被一個terms集合所描述的。 “document”和“term”這兩個詞彙是IR中的術語,它們是來自“圖書館管理學”的。通常一個document認為是一塊文字,(Usually a document is thought of as a piece of text, most likely in a machine readable form), 而一個term則是一個詞語或短語以用作描述document的,在document中大多數會存在著多個term,例如某個document是跟_口腔_ _衛生_相關的,那麼可能會存在著以下的terms:“tooth”、“teeth”、“toothbrush”、“decay”、“cavity”、“plaque”或“diet”等等。

如果在一個IR系統中,存在一個名為D的document,此document被一個名為t的term所描述,那麼t被認為索引了D,可以用以下式子表 示:t->D。在實際應用的一個IR系統中通常是多個documents,如D1, D2, D3 …組成的集合,且有多個term,如t1, t2, t3 …組成的集合,從而有以下關係:ti -> Dj。

如果某個特定的term索引了某個特定的document,那麼稱之為posting,說白了posting就是帶position資訊的term,在相關度檢索中可能有一定的用途的。

給定一個名為D的document,存在著一個terms列表索引著它,我們稱之為D的term list。

給定一個名為t的term,它索引著一個documents列表,這稱之為t的posting list(使用“Document list”可能會在叫法上更一致,但聽起來過於空泛)。

在一個存在於計算機的IR系統中,terms是儲存於索引檔案中的。term可以用作有效地查詢它的posting list,在posting list裡,每一個document帶有一個很短的識別符號,就是document id。簡單來說,一個posting list可以被認為是一個由document ids組成的集合,而term list則是一個字串組成的集合。在某些IR系統的內部是使用數字來表示term的,因此在這些系統中,term list則是數字組成的集合,而Xapian則不是這樣,它使用原汁原味的term,而使用字首來壓縮儲存空間。

Terms不一定是要是document中出現的詞語,通常它們會被轉換為小寫,而且往往它們被詞幹提取演算法處理過,因此透過一個值為“connect” 的term可能會檢索出一系列的詞語,例“connect”、“connects”、“connection”或“connected”等,而一個詞語 也可能產生多個的terms,例如你會將提取出的詞幹和未提取的詞語都索引起來。當然,這可能只適用於英語、法語或拉丁語等歐美系列的語言,而中文的分詞 則有很大的區別,總的來說,歐美語系的語言分詞與中文分詞有以下的區別:

l. 拿英語來說,通常情況下英語的每一個詞語之間是用空格來隔開的,而中文則不然,甚至可以極端到整篇文章都不出現空格或標點符號。 2. 像上面提到的,“connect”、“connects”、“connection”或“connected”分別的意思“動詞性質的連線”、“動詞性質 的第三人稱的連線”、“名稱性質的連線”或“連線的過去式”,但在中文裡,用“連線”就可以表示全部了,幾乎不需要詞幹提取。這意味著英語的各種詞性大部 分是有章可循的,而中文的詞性則是天馬行空的。 3. 第二點只是中文分詞非常困難的一個縮影,要完全正確地標識出某個句子的語意是很困難的,例如“中華人民共和國成立了”這個句子,可以分出“中華”、“華 人”、“人民”、“共和國”、“成立”等詞語,不過其中“華人”跟這個句子其實關係不大。咋一眼看上去很簡單,但機器那有這麼容易懂這其中的奧妙呢?

Values

Values是附加在document上一種後設資料,每一個document可以有多個values,這些values透過不同的數字來標識。 Values被設計成在匹配過程中快速地訪問,它們可以用作排序、排隊多餘重複的document和範圍檢索等用途。雖然values並沒有長度限制,但 最好讓它們儘可能短,如果你僅僅是想儲存某個欄位以便作為結果顯示,那麼建議您最好將它們儲存在document的data中。

Document data

每一個Document只有一個data,可以是任意型別格式的資料,當然在儲存的時候請先轉換為字串。這聽上去可能有點古怪,實情是這樣的:如果要存 儲的資料是文字格式,則可以直接儲存;如果要儲存的資料是各種的物件,請先序列化成二進位制流再儲存,而在讀取的時候反序列化讀取。

posting

posting是帶position的term.

# -*- coding: gb18030 -*-
import xapian
testdatas = [u'abc test python1',u'abcd testing python2']
def buildtest():
    database = xapian.WritableDatabase('indexes/', xapian.DB_CREATE_OR_OPEN)
    stemmer = xapian.Stem("english")
    for data in testdatas:
        doc = xapian.Document()
        doc.set_data(data)
        for term in data.split():
            doc.add_term(term)
        database.add_document(doc)
if __name__ == '__main__':
    buildtest()

執行後,當前目錄下生成索引庫。

[sh]

[ec2-user@ip-10-167-6-221 indexes]$ ll

總用量 52

-rw-rw-r-- 1 ec2-user ec2-user    0  7月 28 16:06 flintlock

-rw-rw-r-- 1 ec2-user ec2-user   28  7月 28 16:06 iamchert

-rw-rw-r-- 1 ec2-user ec2-user   13  7月 28 16:06 postlist.baseA

-rw-rw-r-- 1 ec2-user ec2-user   14  7月 28 16:06 postlist.baseB

-rw-rw-r-- 1 ec2-user ec2-user 8192  7月 28 16:06 postlist.DB

-rw-rw-r-- 1 ec2-user ec2-user   13  7月 28 16:06 record.baseA

-rw-rw-r-- 1 ec2-user ec2-user   14  7月 28 16:06 record.baseB

-rw-rw-r-- 1 ec2-user ec2-user 8192  7月 28 16:06 record.DB

-rw-rw-r-- 1 ec2-user ec2-user   13  7月 28 16:06 termlist.baseA

-rw-rw-r-- 1 ec2-user ec2-user   14  7月 28 16:06 termlist.baseB

-rw-rw-r-- 1 ec2-user ec2-user 8192  7月 28 16:06 termlist.DB

我們下篇再介紹如何去查詢索引。


相關文章