本文及后面关于Lucene的文章所采用的lucene 版本为8.1.0.
1. 什么是tim文件
tim
文件主要作用是保存term的值及term的一些统计信息,如term的频率,doc的频率。
2. tim文件格式
3. 测试代码及结果
public static void main(String[] args) {
try {
// initialization
Directory index = new NIOFSDirectory(Paths.get("/tmp/lucene/test_two"));
IndexWriterConfig config = new IndexWriterConfig();
IndexWriter writer = new IndexWriter(index, config);
Document doc = new Document();
TextField textField = new TextField("title", "lucene test, hello word, nice, nice", Field.Store.YES);
doc.add(textField);
writer.addDocument(doc);
Document doc2 = new Document();
TextField t2 = new TextField("title", "nice haha", Field.Store.YES);
doc2.add(t2);
writer.addDocument(doc2);
writer.commit();
} catch (Exception e) {
e.printStackTrace();
}
doc0 text 内容为: 'lucene test, hello word, nice, nice'
doc1 text 内容为: 'nice data'
得到的分词结果(lucene 会将最终的term安字典排序)为:
term | doc/ doc freq | term freq | pos |
---|---|---|---|
haha | 1/1 | 1 | 1 |
hello | 0/1 | 1 | 2 |
lucene | 0/1 | 1 | 0 |
nice | 0, 1 /2 | 3 | 4,5/0 |
test | 0/1 | 1 | 1 |
word | 0/1 | 1 | 3 |
说明:
- doc/doc freq. 代表该term的包含此term的docId和 docFreq, 以haha为列, 在doc 1出现过,且仅有doc1出现,nice在doc 0, doc 1出现,孤doc freq = 2
- term freq. 代表在所有文档中,term 出现的次数, nice的总出现次数为3, doc 0 出现两次,doc 1 出现1次
- pos 代表该term 在所在的文档中的position, 以nice 来说,在doc0 的position为4, 5, 在doc1的position为0
为什么term最终的顺序是
haha hello lucene nice test word
? lucene 在构造索引的时候会将所有term按字典排序,一方面是易于查找,另一方面是排好序的term在构FST索引时占用空间最小
4. Tim 文件
5. 文件内容分析
5.1 文件头
文件头部分包含两个头内容 BlockTreeTermsDict
和 Lucene50PostingsWriterTerms
, 这两个头内容基本一致。本部分源码在BlockTreeTermsWriter
的274和283行
5.1.1 BlockTreeTermsDict 内容
-
3fd7 6c17
固定头MAGIC -
12
为BlockTreeTermsDict长度18 -
42 6c6f 636b 5472 6565 5465 726d 7344 6963
18个字节即BlockTreeTermsDict -
00 0000 03
4个字节的BlockTreeTermsReader.VERSION_CURRENT
-
e7 b872 3275 fbea 57cd 23fa 3f4a 2696 30
16个字节的segmentId, 这个是随机生成的 -
0a
segment suffix 长度 10 -
4c75 6365 6e65 3530 5f30
10个字节的segment suffix内容即Lucene50_0
5.1.2 Lucene50PostingsWriterTerms 内容
- 同5.1.1 的1)
-
1b
为Lucene50PostingsWriterTerms的长度27 -
4c 7563 656e 6535 3050 6f73 7469 6e67 7357 7269 7465 7254 6572 6d73
即Lucene50PostingsWriterTerms -
0000 0001
4个字节的VERSION_IMPACT_SKIP_DATA - 同5.1.1中的5)
- 同5.1.1中的6)
- 同5.1.1中的7)
5.2 term 数据内容
在上述代码中插入了两个doc, 每一个doc 仅有一个field title, 通过分词后,总共有6个term,
term | doc/ doc freq | term freq |
---|---|---|
haha | 1/1 | 1 |
hello | 0/1 | 1 |
lucene | 0/1 | 1 |
nice | 0, 1 /2 | 3 |
test | 0/1 | 1 |
word | 0/1 | 1 |
现在开始分析term 部分
8001
block size。 每个field分为若干block, 每个block最大为128个term,8001
为Vint编码,关于lunece中编码方式后面会针对性的说明0d
即13, 13 = 6 * 2 + 1, 其中的6为对应terms数量, 具体计算逻辑在 BlockTreeTermsWriter#writeBlock的668行,对应tim文件格式图term个数
43
即67 , 67 = 33 * 2 + 1, 其中的33为6个term占用空间大小, 具体计算逻辑在BlockTreeTermsWriter#writeBlock 820行. 对应tim文件格式图term占用空间
接下来33 个字节为terms内容,首先是term的size, 然后是term的值
04 6861 6861 0568 656c 6c6f 066c 7563 656e 6504 6e69 6365 0474 6573 7404 776f 7264
对应tim文件格式图term1 到term n长度与值
部分0c
12 代表接下的12字节为term的docFreq
与totalTermFreq
对应tim文件格式图doc freq term freq 占用大小
01 0001 0001 0002 0101 0001 00
依次为每一个term的docFreq与(totalTermFreq - docFreq)值 对应tim文件格式图doc freq term freq 值
部分11
17个字节, 接下来的17个字节为meta数据,主要记录term在doc文件与pos文件中偏移及term的docId, 以三个字节为一组,当term所在的doc中包含term次数大于1时,term次数值会保存在pos文件中。 17 = 5 * 3 + 25e 3d 01
第一个termhaha
的元信息,5e
代表第一term在doc文件中偏移,仔细观察doc文件,可以知道5e
(00)恰好是doc data 起始offset,3d
是haha
在pos文件中偏移, 仔细观察pos文件的3d
位置为1,正好为为haha的postition,01
代表doc 100 01 00
为term hello的元数据,00 01
采用delta编码, 也就是说 term的 doc data offset 为5e
, position offset 为3e
, 最后00
代表 doc 000 01 00
为term lucene 的元数据,00 01
采用delta编码, 也就是说 term的 doc data offset 为5e
, position offset 为3f
, 最后00
代表 doc 000 01
为term nice的元数据,00 01
采用delta编码, 也就是说 term的 doc data offset 为5e
, position offset 为40
, nice的term doc freq 大于1, 此部分信息保存在doc文件中03 03 00
为term test 的元数据,00 01
采用delta编码, 也就是说 term的 doc data offset 为5e
, position offset 为43
, 最后00
代表 doc 000 01 00
为term test 的元数据,00 01
采用delta编码, 也就是说 term的 doc data offset 为5e
, position offset 为44
, 最后00
代表 doc 0
5.3 field 元数据区
field元数据区主要存储着以field为单位一些统计信息,源码在BlockTreeTermsWriter#close 详细如下
01
. 即1, 为对应field的数量,对应tim文件格式图field size n
部分。 接着为每个field元数据00
对filed info number, lucene内部为第一个field分配一个field number 对应tim文件格式图field info number
部分06
terms 个数 对应tim文件格式图num terms
部分02
root code length 对应tim文件格式图rootcode length
部分de 03
root code 内容,对应tim文件格式图root code
部分08
所有term的总的frequency, 8 = (1 + 1 + 1 + 3 + 1 + 1) 对应tim文件格式图sumTotal TermFreq
部分07
所有term的总的doc freq, 7 = (1 + 1 + 1 + 2 + 1 + 1) 对应tim文件格式图sumDoc Freq
部分02
doc 数量 对应tim文件格式图docCount
部分02
long size 固定为2 对应tim文件格式图longsSize
部分04 6861 6861
最小term, 04 表示长度,后面4个字节为内容 对应tim文件格式图minTerm
部分0477 6f72 6400
最大term, 04 表示长度,后面4个字节为内容 对应tim文件格式图maxTerm
部分00 0000 0000 0000 b9
8字节的long 这个是filed meta 在tim文件的偏移, 185, 对应tim文件格式图filedMeta offset
部分
5.3 footer区
footer区主要有以下内容
-
c0 2893 e8
MAGIC值,为header值的反码 -
00 0000 00
固定4个字节int 值为0 -
00 0000 00fb 0975 84
8个字节的CRC码
觉得本文有帮助的话,请关注我的简书,一同进步!