标签:
本文转载自:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html 略有删减和补充
上面曾经交代过,Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息,也包括了从Term到Document映射的反向信息,还有其他一些Lucene特有的信息。下面对这三种信息一一介绍。
Index –> Segments (segments.gen, segments_N) –> Field(fnm, fdx, fdt) –> Term (tvx, tvd, tvf)
上面的层次结构不是十分的准确,因为segments.gen和segments_N保存的是段(segment)的元数据信息(metadata),其实是每个Index一个的,而段的真正的数据信息,是保存在域(Field)和词(Term)中的。
一个索引(Index)可以同时存在多个segments_N(至于如何存在多个segments_N,在描述完详细信息之后会举例说明),然而当我们要打开一个索引的时候,我们必须要选择一个来打开,那如何选择哪个segments_N呢?
Lucene采取以下过程:
IndexInput genInput = directory.openInput(IndexFileNames.SEGMENTS_GEN);//"segments.gen" |
if (genA > genB) |
(如上一段描述很蛋疼,为什么会由两个来确定N?留作日后处理)
如下图是segments_N的具体格式:
//在DirectoryReader中有一下函数。 public boolean isCurrent() throws CorruptIndexException, IOException { |
IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED); //文档一为:Students should be allowed to go out with their friends, but not allowed to drink beer. //文档二为:My friend Jerry went to school to see his students but found them drunk which is not allowed. writer.commit();//提交两篇文档,形成_0段。 writer.deleteDocuments(new Term("contents", "school"));//删除文档二 |
IndexWriter.applyDeletes() -> DocumentsWriter.applyDeletes(SegmentInfos) -> reader.deleteDocument(doc); |
IndexWriter.commit() -> IndexWriter.applyDeletes() -> IndexWriter$ReaderPool.release(SegmentReader) -> SegmentReader(IndexReader).commit() -> SegmentReader.doCommit(Map) -> SegmentInfo.advanceDelGen() -> if (delGen == NO) { |
IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED); indexDocs(writer, docDir);//索引两篇文档,一篇包含"school",另一篇包含"beer" 形成的索引文件如下: |
IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED); //flush生成segment "_0",并且flush函数中,flushDocStores设为false,也即下个段将同本段共享域和词向量信息,这时DocumentsWriter中的docStoreSegment= "_0"。 indexDocs(writer, docDir); //commit生成segment "_1",由于上次flushDocStores设为false,于是段"_1"的域以及词向量信息是保存在"_0"中的,在这个时刻,段"_1"并不生成自己的"_1.fdx"和"_1.fdt"。然而在commit函数中,flushDocStores设为true,也即下个段将单独使用新的段来存储域和词向量信息。然而这时,DocumentsWriter中的docStoreSegment= "_1",也即当段"_2"存储其域和词向量信息的时候,是存在"_1.fdx"和"_1.fdt"中的,而段"_1"的域和词向量信息却是存在"_0.fdt"和"_0.fdx"中的,这一点非常令人困惑。 如图writer.commit的时候,_1.fdt和_1.fdx并没有形成。 indexDocs(writer, docDir); //段"_2"形成,由于上次flushDocStores设为true,其域和词向量信息是新创建一个段保存的,却是保存在_1.fdt和_1.fdx中的,这时候才产生了此二文件。 indexDocs(writer, docDir); //段"_3"形成,由于上次flushDocStores设为false,其域和词向量信息是共享一个段保存的,也是是保存在_1.fdt和_1.fdx中的 indexDocs(writer, docDir); //段"_4"形成,由于上次flushDocStores设为false,其域和词向量信息是共享一个段保存的,也是是保存在_1.fdt和_1.fdx中的。然而函数commit中flushDocStores设为true,也意味着下一个段将新创建一个段保存域和词向量信息,此时DocumentsWriter中docStoreSegment= "_4",也表明了虽然段"_4"的域和词向量信息保存在了段"_1"中,将来的域和词向量信息却要保存在段"_4"中。此时"_4.fdx"和"_4.fdt"尚未产生。 indexDocs(writer, docDir); //段"_5"形成,由于上次flushDocStores设为true,其域和词向量信息是新创建一个段保存的,却是保存在_4.fdt和_4.fdx中的,这时候才产生了此二文件。 indexDocs(writer, docDir); //段"_6"形成,由于上次flushDocStores设为false,其域和词向量信息是共享一个段保存的,也是是保存在_4.fdt和_4.fdx中的 |
非复合文件: |
复合文件: |
读取此文件格式参考SegmentInfos.read(Directory directory, String segmentFileName):
|
一个段(Segment)包含多个域,每个域都有一些元数据信息,保存在.fnm文件中,.fnm文件的格式如下:
要了解域的元数据信息,还要了解以下几点:
//声明一个特殊的域和特殊的词 public static final String ID_PAYLOAD_FIELD = "_ID"; public static final String ID_PAYLOAD_TERM = "_ID"; public static final Term ID_TERM = new Term(ID_PAYLOAD_TERM, ID_PAYLOAD_FIELD); //声明一个特殊的TokenStream,它只生成一个词(Term),就是那个特殊的词,在特殊的域里面。 static class SinglePayloadTokenStream extends TokenStream { SinglePayloadTokenStream(String idPayloadTerm) { void setPayloadValue(byte[] value) { public Token next() throws IOException { //对于每一篇文档,都让它包含这个特殊的词,在特殊的域里面 SinglePayloadTokenStream singlePayloadTokenStream = new SinglePayloadTokenStream(ID_PAYLOAD_TERM); long id = 0; |
FieldInfos.read(IndexInput, String)
|
Document FieldsReader.doc(int n, FieldSelector fieldSelector)
|
词向量信息是从索引(index)到文档(document)到域(field)到词(term)的正向信息,有了词向量信息,我们就可以得到一篇文档包含那些词的信息。
TermVectorsReader.get(int docNum, String field, TermVectorMapper)
|
更多的关于文档打分的内容参考下一篇。
标签:
原文地址:http://www.cnblogs.com/HouZhiHouJueBlogs/p/4180436.html