【Lucene】Lucene 学习之索引文件结构

 Lucene 索引文件结构

基本概念

  • 索引(index)
    • Lucene的索引由许多个文件组成,这些文件放在同一个目录下
  • 段(segment)
    • 一个Lucene的索引由多个段组成,段与段之间是独立的。添加新的文档时可以生成新的段,达到阈值(段的个数,段中包含的文件数等)时,不同的段可以合并。
    • 在文件夹下,具有相同前缀的文件属于同一个段
    • segments.gen 和 segments_N(N表示一个具体数字,eg:segments_5)是段的元数据文件,他们保存了段的属性信息。
  • 文档(document)
    • 文档时建索引的基本单位,一个段中可以包含多篇文档
    • 新添加的文档时单独保存在一个新生成的段中,随着段的合并,不同的文档会合并到至相同的段中。
  • 域(Field)
    • 一个文档有可由多个域(Field)组成,比如一篇新闻,有 标题,作者,正文等多个属性,这些属性可以看作是文档的域。
    • 不同的域可以指定不同的索引方式,比如指定不同的分词方式,是否构建索引,是否存储等
  • 词(Term)
    • 词 是索引的最小单位,是经过词法分词和语言处理后的字符串

 

正向信息: 索引(index)——  文档(document)—— 域(field)—— 词(term)


 

总体结构(图片来自网络)

Lucene的一个index文件存放在同一个文件夹下,由多个文件组成。


 

segments.gen : 用于帮助定位到最新的segments_N。

segments.gen文件格式:,读取gen文件,然后判定Version是否正确,接着读取gen0和gen1,如果两个值相当,那么genB=gen0;

此外,会选择index所在文件夹下的segments_N文件,选择最大的一个作为genA,然后比较genA和genB,找到最大的一个,最后才打开segments_N。

IndexInput genInput = directory.openInput(IndexFileNames.SEGMENTS_GEN);//"segments.gen" 
int version = genInput.readInt();//读出版本号 
if (version == FORMAT_LOCKLESS) {//如果版本号正确 
    long gen0 = genInput.readLong();//读出第一个N 
    long gen1 = genInput.readLong();//读出第二个N 
    if (gen0 == gen1) {//如果两者相等则为genB 
        genB = gen0; 
    } 
}

if (genA > genB) 
    gen = genA; 
else 
    gen = genB;

segments_N:段的元数据信息文件。保存了此索引包含多少个段,每个段包含多少篇文档等信息。

  • Format:
    • 索引文件格式的版本号。由于Lucene是在不断开发过程中的,不同版本的Lucene可能有不同索引文件格式,所以规定了文件格式的版本号。
  • Version  
    • 索引的版本号
  • NameCount
    • 下一个新段的段名
  • SegCount
    • 段的个数

SegCount个段的元数据信息:

  • segment:
    • segName
      • 段名
    • SegSize
      • 此段包含的文档数
      • 包含已经删除,尚未optimize的文档。因为在optimize之前,Lucene的段中包含了所有被索引过的文档,而被删除的文档时保存在.del文件中的,在搜索过程中,是从段中读到了被删除的文档,然后再用.del的标志,将这篇文档过滤掉。
      • optimize时,会触发段的合并,此时不会将已删除的文档合并至新段中。
    • DelGen
      • .del文件的版本号
      • 在optimize之前,删除的文档是保存在.del文件中的。
      • 文档删除的几种方式(可以通过IndexReader或者IndexWriter进行删除)
        • IndexReader.deleteDocument(int docID) 根据文档号删除
        • IndexReader.deleteDocuemnts(Term term) 删除包含此term的文档
        • IndexWriter.deleteDocuemnts(Term term) 删除 包含此term的文档(使用的是InderWriter)
        • IndexWriter.deleteDocuments(Term[] terms) 删除包含这些terms的文档
        • IndexWriter.deleteDocuemnts(Query query) 删除满足次查询的文档
        • IndexWriter.deleteDocuemnts(Query[] queries)删除满足这些查询的文档
        • 原来的版本中Lucene的删除一直是由InderReader来完成的,虽然后来可以同IndexWriter来删除,其实真正还是由IndexReader来完成的。IndexWriter将IndexReader保存在readerpool中,删除的时候从中取出完成少出操作。
        • DelGen 是每当IndexWriter向索引文件中提交删除操作的时候,加1,并生成新的.del文件

 

  segment_N 与 segment 文件格式

 

一个段(Segment)包含多个域,每个域都有一些元数据信息,保存在.fnm文件中,.fnm文件的格式如下:

 

 

的数据信息存储在 .fdt 和 .fdx 文件中:

  其中,.fdx 文件中存放FieldValuesPositon,指向.fdt文件,也就是说 域 的具体数据是存放在fdt文件中的。

  • 域数据文件(fdt):
    • 真正保存存储域(stored field)信息的是fdt文件
    • 在一个段中总共有segment size 篇文档,所有fdt文档中共有segment size 个项,每一个项保存一篇文档的域信息。
    • 每一篇文档对应一个FieldCount,表示此文档包含的域的数目,接着是fieldcount个项,每个项保存一个域的信息
    • 对于每一个域,fieldnum是域号,接着是一个byte,8bit,根据填充的0/1,代表不同的意义,最低一位表示此域是否分词,倒数第二位表示此域保存的是字符串数据还是二进制数据,倒数第三位表示此域是否被压缩。最后存储的是这个存储域的值。

          

 

  • 域索引文件(fdx):
    • 由域数据文件格式可知,每篇文档包含的域的个数、每个存储域的值都是不一样的,因为域数据文件中的segment size篇文档,每篇文档占用的大小也是一样的,那么如何快速在fdt文件中辨别每一篇文档的起始地址和终止地址?如何能够更快的找到第n篇文档的存储域的信息呢?这就需要借组域索引文件
    • 域索引文件也总共有segment size 个项,每篇文档都有一个项,每一项都是一个long,大小固定,每一项都是对应的文档在fdt中的起始地址偏移量。

 

词向量(Term Vector)的数据信息(.tvx, .tvd, .tvf)

  词向量 信息是从索引(index)到文档(document)到域(field)到词(term)的正向信息,有了词向量信息,就可以得到一篇文档包含哪些词的信息。

  • 词向量索引文件(tvx):
    • 一个段(segment)包含N篇文档,此文件就有N项,每一项代表一篇文档
    • 每一项包含两部分信息:第一部分是词向量文档文件(tvd)中此文档的偏移量;第二部分是词向量文件(tvf)中此文档的第一个域的偏移量。
  • 词向量文档文件(tvd):
    • 每一项首先是此文档包含的域的个数NumFields,然后是一个NumFields大小的数组,数组每一项都是域号,然后是(NumField - 1)大小的数组,每一篇文档的第一个域在tvf文件中的偏移量信息存储在 tvx 文件中,而其他(NumFields - 1)个域在 tvf 中的偏移量就是第一个域的偏移量加上这(NumField - 1)个数组的每一项的值。
  • 词向量域文件(tvf):
    • 此文件包含了此段中的所有域,并不对文档做区分,到底第几个域到第几个域是属于那篇文件,是由tvx文件中的第一个域的偏移量以及tvd文件中的(NumField - 1)个域的偏移量来决定哪些域数据那个文档的。
    • 对于每一个域,首先是此域包含的词的个数NumTerms,然后是8bit的byte,最后一位指定是否保存位置信息,倒数第二位表示是否保存偏移量信息。然后是NumTerms个项的数组,每一项代表一个词(Term),对于每一个词,由词的文本TermText,词频TermFreq(词在该文档中出现的次数),词的位置信息,词的偏移量信息。

 

参考:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html

 

posted @ 2018-07-07 00:22  buliang  阅读(5466)  评论(0编辑  收藏  举报