Cluene在建立索引時,主要經歷以下幾個步驟:
- 利用Analyzer對content進行處理,構成一個個token.
- 根據token,構建倒排索引,將索引寫到文件(一個索引包含多個不同類型的文件)。
- 如果有可能,將多個較小的索引文件合併成一個較大的索引文件。
- 重複1-3,直到所有文章處理完畢。
其序列圖如下:
可以看到,整個過程是一個大的loop,可以反覆地添加document,每個doc又包含多個字段和相應的content. 可以看到主要用到類是IndexWriter類和DocumentWriter類,在流程的前半段,主要使用DocumentWriter,Lucene自帶的測試例子是從IndexWriter作爲出發點,並且看不到產生的索引文件,默認生成的索引文件都是在內存中,只是最終合併成一個物理文件放到磁盤上,爲了學習和理解DocumentWriter,我使用的如下的測試例子:
void testDocWriter2(CuTest *tc)
{
SimpleAnalyzer a;
RAMDirectory dir;
Similarity *sim = CL_NS(search)::Similarity::getDefault();
FSDirectory *fs= FSDirectory::getDirectory("E:/xxxx",true);
int maxFieldCount=10000;
DocumentWriter docW(fs,&a,sim,maxFieldCount);
TCHAR* test1 = _T("eating chocolate in a computer lab"); //6 terms
TCHAR* test2 = _T("computer in a computer lab"); //5 terms
TCHAR* test3 = _T("a chocolate lab grows old"); //5 terms
TCHAR* test4 = _T("eating chocolate with a chocolate lab in an old chocolate colored computer lab"); //13 terms
Document testDoc1;
testDoc1.add(*Field::Text(_T("title"),test1,true));
testDoc1.add(*Field::Text(_T("content"),test2,true));
docW.addDocument(newSegmentName(),&testDoc1);
Document testDoc2;
testDoc2.add(*Field::Text(_T("title"),test3,false));
docW.addDocument(newSegmentName(),&testDoc2);
}
這裏添加了兩個doc,其中一個doc,含有兩個field,另一個doc,含有一個field。在創建索引時,Lucene會爲每個doc起一個新的名字(這個名字是永不重複的,並且是不可改變的,即使這個doc被合併後,其name也是不變的)。索引產生的文件都是以這個名字命名,只是擴展名不同。下面詳細講解lucene創建索引的過程:
1-4):準備階段,構建索引數據。
5-6):生成索引信息文件。索引信息文件主要存放fieldinfo信息,包括Field的Name,Field的屬性(是否存儲,是否索引)。是最主要的文件。所有其他的文件都依賴於此文件的內容,這個文件要最新生成,在讀取索引時,也要首先讀取這個文件。
7-8)生成xxx.fdt和xxx.fdx,記錄了索引對應的內容,這樣,在查找時,如果找到了包含索引的文檔,可以把文檔還原出來。
9-13) 生成postingTable並寫入文件的過程,其中 10:InvertDocument()是在構建倒排索引,12.將生成的倒排索引進行排序,用到了快速排序。
這個過程中,產生的文件如下:
1. xxx.tii:Term索引文件 xxx.tis Term數據文件
由於Term數據文件中含有大量的Term,爲了加快查找速度。對Term數據文件,建立了二級甚至三級 “索引”。這就是tii文件,其中用到了跳躍表技術。
2. xxx.freq 和xxx.prox, 記錄了term在doc(確切地講,是field)出現的次數和位置。這裏用到“差值規則和或然跟隨規則".
3. xxx.tvf xxx.tvx xxx.tvd 這幾個文件並不是一定會生成的,只有設置了storeTermVector屬性,纔會生成這幾個文件,主要記錄了term在文檔中的次數。
14). 記錄每個每個字段的權重,默認等於document的權重。
15). 進入建立索引的後半程,當產生的索引文件達到一定個數時,程序會自動將幾個索引文件合併成一個較大的索引文件。主要包含以下幾個部分:
- 合併域:mergeFields()
- 合併詞典和倒排表:mergeTerms();
- 合併標準化因子:mergeNorms();
- 合併詞向量:mergeVectors();
索引合併流程圖如下:
索引合併也是一個比較複雜過程,主要流程如下:
索引文件總體結構: