Lucene (v4.5) 深入学习 (二) —— 文件结构
相比2.X的Lucene,4.X里增加了不少文件,而且内部的数据结构面目全非,看着相当纠结。
各种文件信息的具体格式是这篇文档最关键的部分,同时也是之后理解代码的钥匙。因为整个Lucene的工作其实就是创建,操作和使用这些文件。下表是从官网上找来的文件列表。
| NAME | EXTENSION | BRIEF DESCRIPTION |
|---|---|---|
Segments File |
segments.gen, segments_N | 存储提交时的信息 |
| Lock File | write.lock | 防止多个IndexWriter写同一个文件 |
Segment Info |
.si | 存储段的元数据信息 |
Compound File |
.cfs, .cfe | 一个可选的“虚拟”文件,实际上包含了所有其他索引文件。目的是应对使用文件句柄的系统,防止句柄数量过多。 |
Fields |
.fnm | 存储域的信息(元数据?) |
Field Index |
.fdx | 包含指向域数据的指针 |
Field Data |
.fdt | 存储域数据 |
Term Dictionary |
.tim | 字典,存储了term的信息 |
Term Index |
.tip | 字典的索引 |
Frequencies |
.doc | 存储了term在文档中的频率信息 |
Positions |
.pos | 存储了term在索引中的位置信息 |
Payloads |
.pay | 存储附加到每个位置的元数据信息,如字符偏移量和用户的自定义信息(?) |
Norms |
.nvd, .nvm | 存储了编码了的文档和域的长度和影响因子 |
Per-Document Values |
.dvd, .dvm | 存储编码了的附加的评分因子或其他类型的文档信息 |
Term Vector Index |
.tvx | 存储term在文档中的偏移量 |
Term Vector Documents |
.tvd | 存储每篇文档包含的term向量 |
Term Vector Fields |
.tvf | 存储term向量的域级别(?)信息 |
Deleted Documents |
.del | 存储被删除文档的信息 |
在实际使用中,根据索引合并策略,默认会对其中大部分文件进行合并,最后会生成类似下图的文件结构。
具体格式
segments_N ,segments.gen
segments.gen: GenHeader, Generation, Generation
segments_N结构见下图
- Header记录了版本数字和用以标识文件的字符串。示意图中不会特意加入这个变量。这个变量在之后会反复出现,忽略介绍。
- Version记录了索引被更改的次数。更改操作包括添加和删除。
- NameCounter用于生成新的段文件的名字。
- SegCount记录所包含的段的数量。
- SegName是段的名字,同时用于同一个段的所有索引文件的文件名前缀。
- DelGen记录段执行删除文件操作的次数。
- DeletionCount记录段中被删除(标记为删除)的文件的数量。
- Checksum用来验证打开的索引文件的完整性。
- SegCodec段的编解码器的名字。
- CommitUserData存储一个用户提供的不透明的Map<String,String>结构给IndexWriter.setCommitData(java.util.Map)(暂时不知道其作用)
- FieldInfosGen记录段生成(?)fieldInfos文件的次数。
- UpdatesFiles存储在段中更新过的文件的列表。
write.lock
如果write.lock文件存在,那么说明当前有一个writer正在修改index。这个锁文件确保同一时间只有一个writer修改Index。
.si
- SegVersion是段所基于的Lucene的版本。
- SegSize段所包含的文档数。
- IsCompoundFile记录了这个段是不是复合的。(这个还不太理解,可能是“合并过的”的意思。不过那样的话似乎应该用“merge”)如果值是-1则不是,1则是。
- Checksum用于确认文件的完整性。
- The Diagnostics Map作为调试工具由IndexWriter自己(私有地)为每个段创建。它包含了像Lucene的版本,OS信息,Java的版本,段创建的原因(合并,从内存生成,添加索引等)等元信息。
- Attributes编解码器自己的属性,是一个Map。
- Files是段所包括的文件列表。
.cfs, .cfe
- FileData就是这个段所包含的(原始)文件。
.fnm
- FieldsCount文件(段)中所包含的域的数量。
- FieldName域的名字(一个UTF-8的字符串)。
- FieldNumber域的数量。注意相比于之前版本的Lucene,这个版本的域的数量不是隐含在它们的顺序编号中,而是显式地给出。
- FieldBits一个字节,包括了域的各种选项(可选特征)。(从低位开始)
- 标志这个域是否是索引的。1表示需要索引,0表示不需要索引。
- 标志这个域是否有term向量。1表示有,0表示没有。
- 标志偏移量是否设置。如果是1则在位置后添加偏移量。
- 没有使用。Fourth bit is unused.
- 如果设置,这个(索引)域忽略标准化。
- 如果设置,则用户的有效荷载(payload)会被储存在这个域。
- 如果设置,term的频率和位置会被忽略。
- 如果设置,term的位置会被忽略。
- DocValuesBits(一个字节)记录了每个文档的值类型。低位的四个bit表示DocValues的可选特征,高位的四个bit则表示了标准化的可选特征。其中DocValues的选择包括:
- 0: 这个域没有DocValues
- 1: NumericDocValues. (FieldInfo.DocValuesType.NUMERIC)
- 2: BinaryDocValues. (DocValuesType#BINARY)
- 3: SortedDocValues. (DocValuesType#SORTED)
- DocValuesGen表示DocValues的代数。如果是-1,表示这个域没有更新DocValues。
- Attributes编解码器自己的属性,是一个Map。
.fdt
- PackedIntsVersion :PackedInts.VERSION_CURRENT(VInt)暂时不知道具体做什么。
- ChunkCount的值事先是不知道的。这个值表示段中存储所有文档所需要的Chunk数。
- Chunk 包括了DocBase, ChunkDocs, DocFieldCounts, DocLengths,
DocBase这个Chunk中第一篇文档的ID(VInt)。
ChunkDocs 这个Chunk中所包含的文档数(VInt)。
DocFieldCounts 这个Chunk中所包含的每一个文档所包含的域的数量,具体编码方式为:- 如果chunkDocs=1,也就是说这个Chunk中只有一篇文档,那么这个值就是这篇文档的域的数量,并被编码为VInt
- 否则则读取一个VInt(这里称为bitsRequired)。如果bitsRequired是0,那么所有文档的域的数量都是一样的,并且具体数值等于下一个(接下来)的VInt的值。否则bitsRequired是可以用来存储任何值的bit的数目,并且这些值被存储在一个包装好的队列(array)中,在这个队列中每个值的长度都是bitsRequired个bit。
- DocLengths这个Chunk中所有文档的长度,编码方式同DocFieldCounts。
- Compressed Docs一个压缩了的,使用LZ4。
- 一共有ChunkDocs 个ChunkDocs
- FieldNumAndType一个VLong型量。其中最后三位表示Type,其他的位则是FieldNum。
FieldNum:域的ID
Type:- 0: String
- 1: BinaryValue
- 2: Int
- 3: Float
- 4: Long
- 5: Double
- 6, 7: 未使用
- Value也就是具体的值,值的类型依据Type。其中BinaryValue的格式为:
- BinaryValue –> ValueLength ValueLength
.fdx
.fdx:Header, ChunkIndex
.fdx,ChunkIndex的结构可以见CompressingStoredFieldsIndexWriter。比较复杂,如有时间再把内容翻译出来。
2014-3-25:继续学习过程中发现要把.tim,.tip讲得更清楚些还需要补充不少东西,于是决定在这篇里把这两个文件的相关内容去掉,在下一篇中深入讨论。
作者:明翼(XGogo)
-------------
公众号:TSparks
微信:shinelife
扫描关注我的微信公众号感谢
-------------






浙公网安备 33010602011771号