一. consumer的來源
接著上一小節的內容, 還是從這一段程式(位於DocumentWriter.updateDocument(Document, Analyzer, Term) 中繼續.
try {
// This call is not synchronized and does all the
// work
final DocWriter perDoc = state.consumer.processDocument();
// This call is synchronized but fast
finishDocument(state, perDoc);
success = true;
}
第一句話就是產生索引的一個過程, 下面我將詳細的剖析這個過程.
首先一個問題就是:consumer是怎麼來的? 什麼時候初始化的, 我們用單步程式的方法來看看.
state是從上一節提到的
synchronized DocumentsWriterThreadState getThreadState(Document doc, Term delTerm)
中得到的, 我們進去看看... 原來是這一句話,
state = newArray[threadStates.length] = new DocumentsWriterThreadState(this);
跟蹤進去看看, DocumentWriterThreadState的建構函式, 發現了這一句:
consumer = docWriter.consumer.addThread(this);
原來還是從docWriter中來的, 我們繼續查看docWriter裡面是怎樣進行的初始化的.
DocumentsWriter(Directory directory, IndexWriter writer, IndexingChain indexingChain) throws IOException {
//...省略了
consumer = indexingChain.getChain(this);
if (consumer instanceof DocFieldProcessor) {
docFieldProcessor = (DocFieldProcessor) consumer;
}
}
咱們再看看indexingChain.getChain(this)這個方法是怎麼回事
再跟蹤進去, 就真相大白了:
DocConsumer getChain(DocumentsWriter documentsWriter) {
// Build up indexing chain:
final TermsHashConsumer termVectorsWriter = new TermVectorsTermsWriter(documentsWriter);
final TermsHashConsumer freqProxWriter = new FreqProxTermsWriter();
final InvertedDocConsumer termsHash = new TermsHash(documentsWriter, true, freqProxWriter,
new TermsHash(documentsWriter, false, termVectorsWriter, null));
final NormsWriter normsWriter = new NormsWriter();
final DocInverter docInverter = new DocInverter(termsHash, normsWriter);
return new DocFieldProcessor(documentsWriter, docInverter);
}
這個就是一個非常典型的 裝飾者 + 責任鏈 模式, 這樣當我們運行:
final DocWriter perDoc = state.consumer.processDocument();
時, 就會在IndexChain內部進行一系列的擊鼓傳花似的活動, 最終得到處理後的文檔.
二. IndexChain的運轉過程
前面說了, IndexChian就是一個擊鼓傳花的過程, 那這個花是怎麼傳的呢? 讓我們來揭開這個迷
我畫了一個流程圖, 希望可以講得更清楚一點, 另外我先說明一的顏色所代表的含義, 同樣的顏色表示的是在同一個類中啟動並執行過程. 箭頭的指向表示過程或者關係, 比如說 DocInverterPerThread就是DocFieldProcessorPerThread的一個consumer. 前面的數字表示調用的順序
1)的入口就是processDocument, 下面調用了一系列的startDocument()函數, 這些函數的作用是對之後做postings所使用的consumer, processor進行初始化, 其實大部分的startDocument()內容為空白, 顯然, 這是Lucene的開發人員為後面的人所預留的一個介面. 這6部可以認為是初始化的內容.
然後下面一張圖就是處理的一個具體內容了:
先從類命名來說說吧. 可以大概看出, 跟consumer相關的類有幾種主要的命名規則:
1) 結尾帶有Processor的, 這些類是一個基類, 負責調用結尾結尾是Consumer.
2) 結尾帶有Consumer的, 這些類通常被Processor來調用
3) 結尾帶有PerThread的, 這些類負責調用PerField的
也可以認為, PerThread是負責調用一系列的PerField, 為什麼這樣設計我也不能完全說清楚, 如果有哪些朋友知道請指教.
接下來我將詳細的說說TermHashPerField.add()方法, 這個方法是把一個Term加入到Posting表中的過程, 我非常希望能夠理解大部分的內容, 如果有錯誤或者不清楚的地方也希望大家能夠不吝賜教