3.2.9 索引文件格式
在Lucene中,倒排索引结构存储在二进制格式的多个索引文件中,其中以tis为后缀的文件中包含单词信息;frq后缀的文件记录单词的文档编号和这个单词在文档中出现了多少次,也就是频率信息;prx后缀的文件包含单词出现的位置信息。
Lucene把和一个索引相关的文件全部放在一个目录下。其中既存储描述索引结构的元数据,又包含索引数据。每类信息放在不同后缀的二进制文件中。元数据包含以fnm为后缀的列信息文件。列信息文件的格式如下:
字段数量,<字段名称,字段的二进制位描述>
其中,“字段数量”表示索引中字段的数量;“字段名称”是用字符串表示的字段的名称;“字段的二进制位描述”是个byte值和int值。byte值用1个最低位表示是否索引这个字段。
例如:
doc.add(new Field("text", "content", Field.Store.NO, Field.Index.TOKENIZED));
在列信息文件中存储成:
1, <content, 0x01>
词典文件以tis为后缀。这个文件中的词是按顺序存放的。词首先按词对应的字段名称排序,然后按词的正文排序。词典文件的格式如下:
词的数量,<词,词的文档频率>
词用前缀压缩的方式存储,格式是:前缀的长度,后缀,字段编号。“词的文档频率”指词在多少个文档中出现过。排好序的词表中,前后两个词往往包括共同的前缀。“前缀的长度”变量是表示与前一项相同的前缀的字数。例如,如果前一个词是“bone”,后一个是“boy”的话,前缀的长度值为2,后缀值为“y”。
例如有两个文档,内容如下。
文档1:Penn State Football …football。
文档2:Football players … State。
在索引中的存储形式如下:
4, <<0, football,1>,2> <<0, penn,1>, 1> <<1, layers,1>,1> <<0, state,1>,2>
词典文件太大,为了能把词信息完整地读入内存,设计出了词信息索引文件(.tii)。词信息索引文件不存储词本身,但是保存随机读取的文件的位置信息。
词在文档中出现的频率文件以frq为文件后缀。词频率首先是按照tis中的词序来排列,在每个词存储信息,存储这个词在文档中出现的频率,按照docID排序。频率文件中并没有存储docID,而是存储与前后两个docID的增量相关的一个值DocDelta。频率文件的格式如下:
<DocDelta[, Freq? ]>
DocDelta同时决定了文档号和频数。详细地说,DocDelta/2表示当前docID相对于前一个docID的偏移量(或者是0,表示这是TermFreqs里面的第一项)。当DocDelta是奇数时表示在该文档中频数为1;当DocDelta是偶数时,则下一个整数表示在该文档中出现的频数。
例如,假设某一项在文档7中出现1次,在文档11中出现3次,在TermFreqs中就存在如下的整数序列:15, 8, 3。
在这里:
15=2*7+1,在文档7中出现频率是1。
8=2*(11-7),在文档11中出现频率>1。
3,在文档11中出现频率=3。
Posting List见表3-3,其对应的频率文件存储内容如下:
表3-3 Posting List
<<2, 2, 3> <3> <5> <3, 3>>
存储词在文档中出现过的位置的位置文件以prx为后缀。TermPositions按照词来排序(依据tis文件中词的位置)。Positions数值按照docID升序排列。实际存储的是PositionDelta值,PositionDelta是当前位置相对于前一个出现位置(或者为0,表示这是第一次在这个文档中出现)的增量值。例如,假设某词在某文档第4项出现,在接下来的一个文档中第5项和第9项出现,将表示为如下的整数序列:4, 5, 4。表3-3对应的位置文件的存储内容如下:
<<3, 64> <1>> <<1> <0>> <<0> <2>> <<2> <13>>
从索引数据可以看出,索引数据是以词为中心组织的。TermPositions类提供了用来遍历一个词的<文档,频率,<位置>* >元组的方法。
Lucene的查询过程访问的文件如图3-6所示。
图3-6 查询访问文件
复合文件格式的索引优化后只有3个文件,其中segments_N和segments.gen是固定不变的,因为这两个文件是在索引级别存在的文件,还有一个是复合索引文件格式(.cfs)。可以通过setUseCompoundFile()方法设定是否使用复合文件格式。