Lucene生成的索引文件

由上文中提到的代码生成的索引文件如下所示:

索引里面保存了 索引文件内容_字段

 

格式都相当怪异,那些这些文件里面都存放了些什么东西?我们先来了解如下名词

a)  段信息(SegmentInfo):它包含段的元数据;

b)  字段名(Field name):它包含了用来构建索引的字段名;

c)  存储的字段值(Stored Field values):它包含每一个文档的属性-值(attribute-value)对的列表,其中属性名为字段的名称,用来存储和文档相关的辅助信息。比如标题,网址或者是一个用来访问数据库的标识符,在进行搜索时用来作为key来取得返回值;

d)  词典(Term Dictionary):包含所有文档的所有索引字段中使用的词,也包含一个词在文档中的数量,和词的频率数据、接近度数据的指针;

e)  词的频率数据(Term Frequency Data):对词典里面的每个词而言,都有其在所有文档中包含数量以及在某一个文档中的数量,如果频率这个属性被省略掉就不会出现;

f)  词的接近度数据(Term Proximity Data):在词典中的每个词在每一个文档中的位置数据,如果位置属性被省略了就不会出现;

g)  标准化系数(Normalization Factors):对文档中的每个字段,存储了一个值为该字段的命中值Lucene在计算每个词的权重的时候都会乘上该标准化系数;

h)  词向量(Term Vectors):对文档中的每一个字段,词向量都可能被存储,一个词向量由词文本以及词的频率组成;

i) 每个文档的值(Per-Document Values):但一般都被加载到内存中用于快速访问,虽然存储的值通常用于作为搜索结果的摘要,但每一个文档的值都是非常有用的,比如在计算评分的时候作为评分系数;

j) 删除的文档(Deleted Documents):用来指示哪些文档被删除的文件

k)

有效文档

.liv

保存有效文档的索引文件信息

(在5.0版本中,只有liv保存有效docid, del文件取消???)

Lucene 5.0 live docs format

The .liv file is optional, and only exists when a segment contains deletions.

Although per-segment, this file is maintained exterior to compound segment files.

 

名称

文件后缀

描述

段文件(Segments File)

segments.gen

segments_N

存储提交点信息

锁文件(Lock File)

write.lock

用来阻止多个indexWriter向同一个文件写数据

段信息(Segments Info)

.si

存储段的元数据信息

复合文件(Compound File)

.cfs , .cfe

一个可选的虚拟文件,包括所有其他索引文件系统频繁用完的文件句柄

字段信息(Fields)

.fnm

存储字段的信息

字段索引(Fields Index)

.fdx

包含指向字段值的指针

字段数据(Field Data)

.fdt

存储文档里面的字段信息

词典(Term Dictionary)

.tim

存储词信息

词索引(Term Index)

.tip

指向词典的索引

频率信息(Frequencies)

.doc

包含那些含有每一个词的频率的文档列表

位置信息(Positions)

.pos

存储词在索引中出现的位置信息

Payloads

.pay

额外存储每个位置的元数据信息,如字符偏移和用户负载

Norms

.nvd , .nvm

文档和字段的length和boost系数的编码

每个文档的值(Per-Document Values)

.dvd , .dvm

额外的得分系数或者每个文档的值信息编码

词向量索引(Term Vector Index)

.tvx

存储文档的偏移数据文件

词向量文件(Term Vector Documents)

.tvd

包含有词向量的文档信息

词向量字段(Term Vector Fields)

.tvf

关于词向量的字段级信息

删除文档(Deleted Documents)

.del

关于什么文件被删除的信息

 

数据存储基本类型

类型名称

说明

Byte

8 bit

UInt16

16 bit 二字节无符号整型,高位优先(short)

UInt32

32 bit四字节无符号整型,高位优先(int)

UInt64

64 bit八字节无符号整型,高位优先(long)

VInt

可变长度整型。0-127单字节,128-16383两字节,类推

VLong

可变长度Long型

Chars

UNICODE字符串

String

写入格式为:VInt,Chars,字符串长度加字符串值

前面4种类型我们可以将其称为简单类型,因为它们的存储单元均为字节Byte,并遵守高位字节先输出,低位字节后输出的原则。下面以Int32类型为例,看一下它在lucene4中的读写情况:

 

  1. public void writeInt(int i) throws
  2. byte)(i >> 24));//先写入高八位
  3. byte)(i >> 16));  
  4. byte)(i >>  8));  
  5. byte) i);//最后写入低八位
  6.   }  
  7. public int readInt() throws
  8. //先输出高位;后输出低位
  9. return ((readByte() & 0xFF) << 24) | ((readByte() & 0xFF) << 16)  
  10. 0xFF) <<  8) |  (readByte() & 0xFF);  
  11.   }  

 

VInt类型可能比较难理解,我们来深入看一下:

·         变长的整数类型,它可能包含多个Byte,对于每个Byte的8位,其中后7位表示数值,最高1位表示是否还有另一个Byte,0表示没有,1表示有。

·         越前面的Byte表示数值的低位,越后面的Byte表示数值的高位。

·         例如130化为二进制为 1000, 0010,总共需要8位,一个Byte表示不了,因而需要两个Byte来表示,第一个Byte表示后7位,并且在最高位置1来表示后面还有一个Byte,所以为(1) 0000010,第二个Byte表示第8位,并且最高位置0来表示后面没有其他的Byte了,所以为(0) 0000001

第一个Byte

第二个Byte

第三个Byte

0

00000000

 

 

2

00000010

 

 

 

 

 

127

01111111

 

 

128

10000000

00000001

 

129

10000001

00000001

 

 

 

 

16383

11111111

01111111

 

16384

10000000

10000000

00000001

16385

10000001

10000000

00000001

 

 

 

我们看一下它具体的读写代码:

 

  1. public final void writeVInt(int i) throws
  2. //后七位之前还有为1的位存在
  3. while ((i & ~0x7F) != 0) {  
  4. //先取出低七位 ,并在第八位补1,指示后面还存在byte
  5. byte)((i & 0x7F) | 0x80));  
  6. 7;  
  7. }  
  8. //写入余下的八位
  9. byte)i);  
  10.   }  
  11.    
  12. public int readVInt() throws
  13. //读取第一个byte
  14. byte
  15. //大于0即最高位为0,没有下一个byte,直接返回
  16. if (b >= 0) return
  17. //获取低七位的值
  18. int i = b & 0x7F;  
  19. //读下一个byte
  20. b = readByte();  
  21. //获取低七位的值并左移七位与之前的七位数据相加
  22. 0x7F) << 7;  
  23. if (b >= 0) return
  24.     b = readByte();  
  25. 0x7F) << 14;  
  26. if (b >= 0) return
  27.     b = readByte();  
  28. 0x7F) << 21;  
  29. if (b >= 0) return
  30.     b = readByte();  
  31. //
  32. 0x0F) << 28;  
  33. if ((b & 0xF0) == 0) return
  34. throw new IOException("Invalid vInt detected (too many bits)");  
  35.   }  

 

VLong的相关读写实现与之类似,只是字节数不一样,这里不再重复介绍。最后看一下String相关:

1. public void writeString(String s) throws
2. final BytesRef utf8Result = new BytesRef(10);  
3. //转码
4. UnicodeUtil.UTF16toUTF8(s, 0, s.length(), utf8Result);  
5. //写入字符串长度
6. writeVInt(utf8Result.length);  
7. //写入字符串值
8. 0, utf8Result.length);  
9.   }  
10. public String readString() throws
11. //读取字符串长度
12. int
13. final byte[] bytes = new byte[length];  
14. //读取一个字符串长度的byte
15. 0, length);  
16. return new String(bytes, 0, length, IOUtils.CHARSET_UTF_8);  
17.   }