标签:
本文转载自: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