摘自:http://forfuture1978.iteye.com/blog/546841

4.2.2. 文档号及词频(frq)信息

文档号及词频文件里面保存的是倒排表,是以跳跃表形式存在的。

  • 此文件包含TermCount个项,每一个词都有一项,因为每一个词都有自己的倒排表。
  • 对于每一个词的倒排表都包括两部分,一部分是倒排表本身,也即一个数组的文档号及词频,另一部分是跳跃表,为了更快的访问和定位倒排表中文档号及词频的位置。
  • 对于文档号和词频的存储应用的是差值规则和或然跟随规则,Lucene的文档本身有以下几句话,比较难以理解,在此解释一下:

For example, the TermFreqs for a term which occurs once in document seven and three times in document eleven, with omitTf false, would be the following sequence of VInts:

15, 8, 3

If omitTf were true it would be this sequence of VInts instead:

7,4

首先我们看omitTf=false的情况,也即我们在索引中会存储一个文档中term出现的次数。

例子中说了,表示在文档7中出现1次,并且又在文档11中出现3次的文档用以下序列表示:15,8,3.

那这三个数字是怎么计算出来的呢?

首先,根据定义TermFreq --> DocDelta[, Freq?],一个TermFreq结构是由一个DocDelta后面或许跟着Freq组成,也即上面我们说的A+B?结构。

DocDelta自然是想存储包含此Term的文档的ID号了,Freq是在此文档中出现的次数。

所以根据例子,应该存储的完整信息为[DocID = 7, Freq = 1] [DocID = 11,  Freq = 3](见全文检索的基本原理章节)。

然而为了节省空间,Lucene对编号此类的数据都是用差值来表示的,也即上面说的规则2,Delta规则,于是文档ID就不能按完整信息存了,就应该存放如下:

[DocIDDelta = 7, Freq = 1][DocIDDelta = 4 (11-7), Freq = 3]

然而Lucene对于A+B?这种或然跟随的结果,有其特殊的存储方式,见规则3,即A+B?规则,如果DocDelta后面跟随的Freq为1,则用DocDelta最后一位置1表示。

如果DocDelta后面跟随的Freq大于1,则DocDelta得最后一位置0,然后后面跟随真正的值,从而对于第一个Term,由于Freq为1,于是放在DocDelta的最后一位表示,DocIDDelta = 7的二进制是000 0111,必须要左移一位,且最后一位置一,000 1111 = 15,对于第二个Term,由于Freq大于一,于是放在DocDelta的最后一位置零,DocIDDelta = 4的二进制是0000 0100,必须要左移一位,且最后一位置零,0000 1000 = 8,然后后面跟随真正的Freq = 3。

于是得到序列:[DocDleta = 15][DocDelta = 8, Freq = 3],也即序列,15,8,3。

如果omitTf=true,也即我们不在索引中存储一个文档中Term出现的次数,则只存DocID就可以了,因而不存在A+B?规则的应用。

[DocID = 7][DocID = 11],然后应用规则2,Delta规则,于是得到序列[DocDelta = 7][DocDelta = 4 (11 - 7)],也即序列,7,4.

  • 对于跳跃表的存储有以下几点需要解释一下:

    • 跳跃表可根据倒排表本身的长度(DocFreq)和跳跃的幅度(SkipInterval)而分不同的层次,层次数为NumSkipLevels = Min(MaxSkipLevels, floor(log(DocFreq/log(SkipInterval)))).
    • 第Level层的节点数为DocFreq/(SkipInterval^(Level + 1)),level从零计数。
    • 除了最高层之外,其他层都有SkipLevelLength来表示此层的二进制长度(而非节点的个数),方便读取某一层的跳跃表到缓存里面。
    • 低层在前,高层在后,当读完所有的低层后,剩下的就是最后一层,因而最后一层不需要SkipLevelLength。这也是为什么Lucene文档中的格式描述为 NumSkipLevels-1, SkipLevel,也即低NumSKipLevels-1层有SkipLevelLength,最后一层只有SkipLevel,没有SkipLevelLength。
    • 除最低层以外,其他层都有SkipChildLevelPointer来指向下一层相应的节点。
    • 每一个跳跃节点包含以下信息:文档号,payload的长度,文档号对应的倒排表中的节点在frq中的偏移量,文档号对应的倒排表中的节点在prx中的偏移量。
    • 虽然Lucene的文档中有以下的描述,然而实验的结果却不是完全准确的:

Example: SkipInterval = 4, MaxSkipLevels = 2, DocFreq = 35. Then skip level 0 has 8 SkipData entries, containing the 3rd, 7th, 11th, 15th, 19th, 23rd, 27th, and 31st document numbers in TermFreqs. Skip level 1 has 2 SkipData entries, containing the 15th and 31st document numbers in TermFreqs.

按照描述,当SkipInterval为4,且有35篇文档的时候,Skip level = 0应该包括第3,第7,第11,第15,第19,第23,第27,第31篇文档,Skip level = 1应该包括第15,第31篇文档。

然而真正的实现中,跳跃表节点的时候,却向前偏移了,偏移的原因在于下面的代码:

  • FormatPostingsDocsWriter.addDoc(int docID, int termDocFreq)

    • final int delta = docID - lastDocID;
    • if ((++df % skipInterval) == 0)
      • skipListWriter.setSkipData(lastDocID, storePayloads, posWriter.lastPayloadLength);
      • skipListWriter.bufferSkip(df);

从代码中,我们可以看出,当SkipInterval为4的时候,当docID = 0时,++df为1,1%4不为0,不是跳跃节点,当docID = 3时,++df=4,4%4为0,为跳跃节点,然而skipData里面保存的却是lastDocID为2。

所以真正的倒排表和跳跃表中保存一下的信息:

 

lucene .doc文件格式解析——见图的更多相关文章

  1. ArcGIS三大文件格式解析

    原文:ArcGIS三大文件格式解析 Shape数据 Shapefile是ArcView GIS 3.x的原生数据格式,属于简单要素类,用点.线.多边形存储要素的形状,却不能存储拓扑关系,具有简单.快速 ...

  2. Lucene 全文搜索解析

    一.创建查询对象的方式 对要搜索的信息创建 Query 查询对象,Lucene 会根据 Query 查询对象生成最终的查询语法.类似关系数据库 Sql 语法一样,Lucene 也有自己的查询语法,比如 ...

  3. Android init.rc文件格式解析

    /***************************************************************************** * Android init.rc文件格式 ...

  4. mp4文件格式解析(转载)

    mp4文件格式解析 原作:http://blog.sina.com.cn/s/blog_48f93b530100jz4b.html 目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的 ...

  5. C++PE文件格式解析类(轻松制作自己的PE文件解析器)

    PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣 ...

  6. 解析prototxt文件的python库 prototxt-parser(使用parsy自定义文件格式解析)

    解析prototxt文件的python库 prototxt-parser https://github.com/yogin16/prototxt_parser https://test.pypi.or ...

  7. mp4文件格式解析(转)

    mp4文件格式解析 MP4文件格式带数据详解 MP4文件格式的解析,以及MP4文件的分割算法

  8. Qt的.pro文件格式解析

    Qt的.pro文件格式解析 在Qt中用qmake生成makefile文件,它是由.pro文件生成而来的,.pro文件的具体格式语法如下: 1.注释 .pro文件中注释采用#号,从"#&quo ...

  9. Lucene学习总结之七:Lucene搜索过程解析

    一.Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程. 其可用如下图示: 总共包括以下几个过程: ...

随机推荐

  1. Linux命令学习(5):more和less

    引子 平常工作中经常需要查看很大的文本文件,如果用vi打开的话会非常慢,所以平常都用less,但是并没有很系统地学习过less的用法,今天总结一下less和more的用法. 经过学习我发现less比m ...

  2. Win2008 Server搭建流媒体服务(在线看电影)

    什么是流媒体服务呢. 所谓流媒体是指采用流式传输的方式在Internet播放的媒体格式, 与需要将整个视频文件全部下载之后才能观看的传统方式相比, 流媒体技术是通过将视频文件经过特殊的压缩方式分成一个 ...

  3. Django之模板引擎(母版)

    Django之模板引擎(母版) 母版:存放所有页面的基本信息,基本样式 子班:继承母版 自定义当前页面私有的样式信息 母版的样式: {% block xxx(名称) %} xxxxxxx(数据) {% ...

  4. 带FIFO的UART数据接收

    芯片手册 某个Cortex-M4芯片带有1个UART,支持Tx,Rx 的FIFO功能,而且可以通过寄存器配置FIFO的阈值,芯片的datasheet并不完善,没有说明RX的FIFO具体有几个级别,每隔 ...

  5. Jackson入门

    Jackson 框架,轻易转换JSON Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 前面有介绍过json-lib这个框架,在 ...

  6. [luoguP1015] 回文数(模拟 + 高精度?)

    传送门 类似高精的操作... 代码 #include <cstdio> #include <cstring> #include <iostream> #define ...

  7. CF901C. Bipartite Segments

    n<=300000,m<=300000的图,图上只有奇环,q<=300000个询问每次问:一个区间内有多少个子区间,满足只保留编号在该区间的点以及他们之间的边,可以构成一个二分图. ...

  8. 【存储过程】MySQL存储过程/存储过程与自定义函数的区别

    ---------------------------存储过程-------------------- 语法: 创建存储过程: CREATE [definer = {user|current_user ...

  9. POJ 2778 (AC自动机+矩阵乘法)

    POJ 2778 DNA Sequence Problem : 给m个只含有(A,G,C,T)的模式串(m <= 10, len <=10), 询问所有长度为n的只含有(A,G,C,T)的 ...

  10. ZOJ 4016 Mergeable Stack 链表

    Mergeable Stack Time Limit: 2 Seconds      Memory Limit: 65536 KB Given  initially empty stacks, the ...