段的元数据信息

segments.gensegments_N保存了段的元数据信息,索引有多少个段,每个段有多少篇文档。而段的真正的数据信息是保存在域(Field)和词(Term)中的。

一个索引只有一个segments.gen,而segments_N可能有多个。

IndexReader.open() -> DirectoryReader.open() -> FindSegmentsFile.run() FindSegmentsFile.doBody() -> SegmentInfos.read()

相关辅助类:ChecksumIndexInput

DirectoryReader

通过调用FindSegmentsFile查找应该打开的segmentFileName,然后再调用SegmentInfos.read()去读取段的元数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly,
final int termInfosIndexDivisor) throws CorruptIndexException, IOException {
return (IndexReader) new SegmentInfos.FindSegmentsFile(directory) {
@Override
protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException {
SegmentInfos infos = new SegmentInfos();
// 读取Segment元数据
infos.read(directory, segmentFileName);
if (readOnly)
return new ReadOnlyDirectoryReader(directory, infos, deletionPolicy, termInfosIndexDivisor);
else
return new DirectoryReader(directory, infos, deletionPolicy, false, termInfosIndexDivisor);
}
}.run(commit);
}

SegmentInfos

FindSegmentsFile.run()

以下步骤是确定打开哪个segments_N文件。

  1. 得到 genA
    listAll所有索引目录文件,通过SegmentInfos.getCurrentSegmentGeneration(files);得到genA,基本逻辑是查找segments开头的文件并选择 N 最大的一个作为 genA
  2. 得到 genB
    通过IndexInput的子类读取segments.gen文件,该文件中保存了versiongen1gen2几个值,如果version正确,则比较gen1gen2,两个相等则为genB
  3. 得到 N
    选择genAgenB中最大的一个作为 N。

确定了segments_N文件名后就调用FindSegmentsFile.doBody()方法,其实现调用了SegmentInfos.read(directory, segmentFileName)去读取具体的segments_N文件。

SegmentInfos.read()

  1. 获取 IndexInput 实例
    通过new ChecksumIndexInput(directory.openInput(segmentFileName))得到input实例,
  2. 读取 format, version, counter, segCount
    | 属性 | 描述 |
    |——–|——–|
    |format|索引文件格式的版本号,主要是校验 IndexWriter 和 IndexReader 是否使用了同一个版本号。|
    |version|索引的版本号,记录了 IndexWriter 将修改提交到索引文件中的次数。可以比较 IndexReader 中的 version 和索引文件中的 version 是否相同来判断此 IndexReader 被打开后,还有没有被 IndexWriter 更新。|
    |counter|是下一个新段的段名。|
    |segCount|段的个数。|
  3. 读取每个段的元数据
    SegmentInfos.read()
    1
    2
    3
    for (int i = input.readInt(); i > 0; i--) { // read segmentInfos
    add(new SegmentInfo(directory, format, input));
    }
属性 描述
segName 存储段名。
segSize 存储段中包含的文档数。
delGen .del文件的版本号,每当 IndexWriter 向索引提交删除操作的时候,加1。
docStoreOffset 标志位,域和词向量的存储方式,-1 表示单独存储,否则表示共享存储。
docStoreSegment 保存了共享段的名字。
docStoreIsCompoundFile doc是否存储在 Compound File (.cfx) 文件中
hasSingleNormFile 标志位,1表示所有的 Norm Factor 都存在 .nrm 文件中,否则每个域都有自己的文件 .fN
numField 域的数量
normGen 记录每个域的 norm file
isCompoundFile 是否为复合文件,把同一个段中的文件按照一定的格式保存在一个文件当中,以减少每次打开文件的个数
delCount 记录了此段中删除的文档的数目
hasProx 如果至少有一个段 omitTf 为fase,也即词频需要被保存,则 hasProx 为1,否则为0
diagnostics 调试信息

对于域(Stored Field)词向量(Term Vector)的存储可以有不同的方式,即可以每个段(Segment)单独存储自己的域和词向量信息,也可以多个段共享域和词向量,把它们存储到一个段中去。

  • 如果DocStoreOffset为-1,则此段单独存储自己的域和词向量,从存储文件上来看,如果此段段名为XXX,则此段有自己的XXX.fdt,XXX.fdx,XXX.tvf,XXX.tvd,XXX.tvx文件。DocStoreSegmentDocStoreIsCompoundFile在此处不被保存。
  • 如果DocStoreOffset不为-1,则DocStoreSegment保存了共享的段的名字,比如为YYY,DocStoreOffset则为此段的域及词向量信息在共享段中的偏移量。则此段没有自己的XXX.fdt,XXX.fdx,XXX.tvf,XXX.tvd,XXX.tvx文件,而是将信息存放在共享段的YYY.fdt,YYY.fdx,YYY.tvf,YYY.tvd,YYY.tvx文件中。
  1. 读取 userData
    保存了user在 IndexWriter.commit 提交的信息。
  2. checkSum
    存储了 segment_N 文件的校验和。

感谢:
http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html