Lucene文档结构

4. Lucene文档结构 
Lucene中最基础的概念是索引(index),文档(document),域(field)和项(term)。 
索引包含了一个文档的序列。 
· 文档是一些域的序列。 
· 域是一些项的序列。 
· 项就是一个字串。 
存在于不同域中的同一个字串被认为是不同的项。因此项实际是用一对字串表示的,第一个字串是域名,第二个是域中的字串。 
 
4.1. Lucene概念详细介绍 
4.1.1. 域的类型 
Lucene中,域的文本可能以逐字的非倒排的方式存储在索引中。而倒排过的域称为被索引过了。域也可能同时被存储和被索引。 
域的文本可能被分解许多项目而被索引,或者就被用作一个项目而被索引。大多数的域是被分解过的,但是有些时候某些标识符域被当做一个项目索引是很有用的。 
 
4.1.2. 段(Segment) 
Lucene索引可能由多个子索引组成,这些子索引成为段。每一段都是完整独立的索引,能被搜索。索引是这样作成的: 
1. 为新加入的文档创建新段。 
2. 合并已经存在的段。 
搜索时需要涉及到多个段和/或者多个索引,每一个索引又可能由一些段组成。 
 
4.1.3. 文档号(document.nbspNumber) 
内部的来说,Lucene用一个整形(interger)的文档号来指示文档。第一个被加入到索引中的文档就是0号,顺序加入的文档将得到一个由前一个号码递增而来的号码。 
 
注意文档号是可能改变的,所以在Lucene外部存储这些号码时必须小心。特别的,号码的改变的情况如下: 
 
· 只有段内的号码是相同的,不同段之间不同,因而在一个比段广泛的上下文环境中使用这些号码时,就必须改变它们。标准的技术是根据每一段号码多少为每一段分配一个段号。将段内文档号转换到段外时,加上段号。将某段外的文档号转换到段内时,根据每段中可能的转换后号码范围来判断文档属于那一段,并减调这一段的段号。例如有两个含5个文档的段合并,那么第一段的段号就是0,第二段段号5。第二段中的第三个文档,在段外的号码就是8。 
 
· 文档删除后,连续的号码就出现了间断。这可以通过合并索引来解决,段合并时删除的文档相应也删掉了,新合并而成的段并没有号码间断。 
 
4.1.4. 索引信息 
索引段维护着以下的信息: 
· 域集合。包含了索引中用到的所有的域。 
· 域值存储表。每一个文档都含有一个“属性-值”对的列表,属性即为域名。这个列表用来存储文档的一些附加信息,如标题,url或者访问数据库的一个ID。在搜索时存储域的集合可以被返回。这个表以文档号标识。 
· 项字典。这个字典含有所有文档的所有域中使用过的的项,同时含有使用过它的文档的文档号,以及指向使用频数信息和位置信息的指针。 
· 项频数信息。对于项字典中的每个项,这些信息包含含有这个项的文档的总数,以及每个文档中使用的次数。 
· 项位置信息。对于项字典中的每个项,都存有在每个文档中出现的各个位置。 
· 标准化因子。对于文档中的每一个域,存有一个值,用来以后乘以这个这个域的命中数(hits)。 
· 被删除的文档信息。这是一个可选文件,用来表明那些文档已经删除了。 
接下来的各部分部分详细描述这些信息。 
 
4.1.5. 文件的命名(File Naming) 
同属于一个段的文件拥有相同的文件名,不同的扩展名。扩展名由以下讨论的各种文件格式确定。 
一般来说,一个索引存放一个目录,其所有段都存放在这个目录里,不这样作,也是可以的,在性能方面较低。 
 
4.2. Lucene基本数据类型(Primitive Types) 
4.2.1. 字节Byte 
最基本的数据类型就是字节(byte,8位)。文件就是按字节顺序访问的。其它的一些数据类型也定义为字节的序列,文件的格式具有字节意义上的独立性。 
UInt32 :32位无符号整数,由四个字节组成,高位优先。UInt32 --> <Byte>4 
Uint64 : 64位无符号整数,由八字节组成,高位优先。UInt64 --> <Byte>8 
VInt : 可变长的正整数类型,每字节的最高位表明还剩多少字节。每字节的低七位表明整数的值。因此单字节的值从0到127,两字节值从128到16,383,等等。 
VInt 编码示例 
value 
First byte 
Second byte 
Third byte 

00000000 

00000001 

00000010 
... 
127 
01111111 
128 
10000000 
00000001 
129 
10000001 
00000001 
130 
10000010 
00000001 
... 
16,383 
11111111 
01111111 
16,384 
10000000 
10000000 
00000001 
16,385 
10000001 
10000000 
00000001 
... 这种编码提供了一种在高效率解码时压缩数据的方法。 
 
4.2.2. 字符串Chars 
Lucene输出UNICODE字符序列,使用标准UTF-8编码。 
String :Lucene输出由VINT和字符串组成的字串,VINT表示字串长,字符串紧接其后。 
String --> VInt, Chars 
 
4.3. 索引包含的文件(Per-Index Files) 
4.3.1. Segments文件 
索引中活动的段存储在Segments文件中。每个索引只能含有一个这样的文件,名为"segments".这个文件依次列出每个段的名字和每个段的大小。 
Segments --> SegCount, <SegName, SegSize>SegCount 
SegCount, SegSize --> UInt32 
SegName --> String 
SegName表示该segment的名字,同时作为索引其他文件的前缀。 
SegSize是段索引中含有的文档数。 
 
4.3.2. Lock文件 
有一些文件用来表示另一个进程在使用索引。 
· 如果存在"commit.lock"文件,表示有进程在写"segments"文件和删除无用的段索引文件,或者表示有进程在读"segments"文件和打开某些段的文件。在一个进程在读取"segments"文件段信息后,还没来得及打开所有该段的文件前,这个Lock文件可以防止另一个进程删除这些文件。 
· 如果存在"index.lock"文件,表示有进程在向索引中加入文档,或者是从索引中删除文档。这个文件防止很多文件同时修改一个索引。 
 
4.3.3. Deleteable文件 
名为"deletetable"的文件包含了索引不再使用的文件的名字,这些文件可能并没有被实际的删除。这种情况只存在与Win32平台下,因为Win32下文件仍打开时并不能删除。 
Deleteable --> DelableCount, <DelableName>DelableCount 
DelableCount --> UInt32 
DelableName --> String 
 
4.3.4. 段包含的文件(Per-Segment Files) 
剩下的文件是每段中包含的文件,因此由后缀来区分。 
域(Field) 
域集合信息(Field Info) 
所有域名都存储在这个文件的域集合信息中,这个文件以后缀.fnm结尾。 
 
FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount 
FieldsCount --> VInt 
FieldName --> String 
FieldBits --> Byte 
目前情况下,FieldBits只有使用低位,对于已索引的域值为1,对未索引的域值为0。 
文件中的域根据它们的次序编号。因此域0是文件中的第一个域,域1是接下来的,等等。这个和文档号的编号方式相同。 
 
4.3.5. 域值存储表(Stored Fields) 
域值存储表使用两个文件表示: 
1. 域索引(.fdx文件)。 
如下,对于每个文档这个文件包含指向域值的指针: 
FieldIndex (.fdx) --> <FieldvaluesPosition>SegSize 
FieldvaluesPosition --> Uint64 
FieldvaluesPosition指示的是某一文档的某域的域值在域值文件中的位置。因为域值文件含有定长的数据信息,因而很容易随机访问。在域值文件中,文档n的域值信息就存在n*8位置处(The position of document.nbspn's field data is the Uint64 at n*8 in this file.)。 
2. 域值(.fdt文件)。 
如下,每个文档的域值信息包含: 
FieldData (.fdt) --> <DocFieldData>SegSize 
DocFieldData --> FieldCount, <FieldNum, Bits, value>FieldCount 
FieldCount --> VInt 
FieldNum --> VInt 
Bits --> Byte 
value --> String 
目前情况下,Bits只有低位被使用,值为1表示域名被分解过,值为0表示未分解过。÷ 
 
4.3.6. 项字典(Term Dictionary) 
项字典用以下两个文件表示: 
1. 项信息(.tis文件)。 
TermInfoFile (.tis)--> TermCount, TermInfos 
TermCount --> UInt32 
TermInfos --> <TermInfo>TermCount 
TermInfo --> <Term, DocFreq, FreqDelta, ProxDelta> 
Term --> <PrefixLength, Suffix, FieldNum> 
Suffix --> String 
PrefixLength, DocFreq, FreqDelta, ProxDelta 
--> VInt 
 
项信息按项排序。项信息排序时先按项所属的域的文字顺序排序,然后按照项的字串的文字顺序排序。 
 
项的字前缀往往是共同的,与字的后缀组成字。PrefixLength变量就是表示与前一项相同的前缀的字数。因此,如果前一个项的字是"bone",后一个是"boy"的话,PrefixLength值为2,Suffix值为"y"。 
 
FieldNum指明了项属于的域号,而域名存储在.fdt文件中。 
 
DocFreg表示的是含有该项的文档的数量。 
 
FreqDelta指明了项所属TermFreq变量在.frq文件中的位置。详细的说,就是指相对于前一个项的数据的位置偏移量(或者是0,表示文件中第一个项)。 
 
ProxDelta指明了项所属的TermPosition变量在.prx文件中的位置。详细的说,就是指相对于前一个项的数据的位置偏移量(或者是0,表示文件中第一个项)。 
 
2. 项信息索引(.tii文件)。 
 
每个项信息索引文件包含.tis文件中的128个条目,依照条目在.tis文件中的顺序。这样设计是为了一次将索引信息读入内存能,然后使用它来随机的访问.tis文件。 
这个文件的结构和.tis文件非常类似,只在每个条目记录上增加了一个变量IndexDelta。 
TermInfoIndex (.tii)--> IndexTermCount, TermIndices 
IndexTermCount --> UInt32 
TermIndices --> <TermInfo, IndexDelta>IndexTermCount 
IndexDelta --> VInt 
IndexDelta表示该项的TermInfo变量值在.tis文件中的位置。详细的讲,就是指相对于前一个条目的偏移量(或者是0,对于文件中第一个项)。 
 
4.3.7. 项频数(Frequencies) 
.frq文件包含每一项的文档的列表,还有该项在对应文档中出现的频数。 
FreqFile (.frq) --> <TermFreqs>TermCount 
TermFreqs --> <TermFreq>DocFreq 
TermFreq --> DocDelta, Freq? 
DocDelta,Freq --> VInt 
TermFreqs序列按照项来排序(依据于.tis文件中的项,即项是隐含存在的)。 
TermFreq元组按照文档号升序排列。 
DocDelta决定了文档号和频数。详细的说,DocDelta/2表示相对于前一文档号的偏移量(或者是0,表示这是TermFreqs里面的第一项)。当DocDelta是奇数时表示在该文档中频数为1,当DocDelta是偶数时,另一个VInt(Freq)就表示在该文档中出现的频数。 
例如,假设某一项在文档7中出现一次,在文档11中出现了3次,在TermFreqs中就存在如下的VInts序列: 
15, 22, 3 
 
4.3.8. 项位置(Position) 
.prx文件包含了某文档中某项出现的位置信息的列表。 
ProxFile (.prx) --> <TermPositions>TermCount 
TermPositions --> <Positions>DocFreq 
Positions --> <PositionDelta>Freq 
PositionDelta --> VInt 
TermPositions按照项来排序(依据于.tis文件中的项,即项是隐含存在的)。 
Positions元组按照文档号升序排列。 
PositionDelta是相对于前一个出现位置的偏移位置(或者为0,表示这是第一次在这个文档中出现)。 
例如,假设某一项在某文档第4项出现,在另一个文档中第5项和第9项出现,将存在如下的VInt序列: 
4, 5, 4 
 
4.3.9. 标准化因子(Normalization Factor) 
.nrm文件包含了每个文档的标准化因子,标准化因子用来以后乘以这个这个域的命中数。 
Norms (.nrm) --> <Byte>SegSize 
每个字节记录一个浮点数。位0-2包含了3位的尾数部分,位3-8包含了5位的指数部分。 
按如下规则可将这些字节转换为IEEE标准单精度浮点数: 
1. 如果该字节是0,就是浮点0; 
2. 否则,设置新浮点数的标志位为0; 
3. 将字节中的指数加上48后作为新的浮点数的指数; 
4. 将字节中的尾数映射到新浮点数尾数的高3位;并且 
5. 设置新浮点数尾数的低21位为0。 
 
4.3.10. 被删除的文档(Deleted document) 
.del文件是可选的,只有在某段中存在删除操作后才存在: 
Deletions (.del) --> ByteCount,BitCount,Bits 
ByteSize,BitCount --> Uint32 
Bits --> <Byte>ByteCount 
ByteCount表示的是Bits列表中Byte的数量。典型的,它等于(SegSize/8)+1。 
BitCount表示Bits列表中多少个已经被设置过了。 
Bits列表包含了一些位(bit),顺序表示一个文档。当对应于文档号的位被设置了,就标志着这个文档已经被删除了。位的顺序是从低到高。因此,如果Bits包含两个字节,0x00和0x02,那么表示文档9已经删除了。 
 
4.3.11. 局限性(Limitations) 
在以上的文件格式中,好几处都有限制项和文档的最大个数为32位数的极限,即接近于40亿。今天看来,这不会造成问题,但是,长远的看,可能造成问题。因此,这些极限应该或者换为UInt64类型的值,或者更好的,换为VInt类型的值(VInt值没有上限)。 
 
有两处地方的代码要求必须是定长的值,他们是: 
 
1. FieldvaluesPosition变量(存储于域索引文件中,.fdx文件)。它已经是一个UInt64型,所以不会有问题。 
 
2. TermCount变量(存储于项信息文件中,.tis文件)。这是最后输出到文件中的,但是最先被读取,因此是存储于文件的最前端 。索引代码先在这里写入一个0值,然后在其他文件输出完毕后覆盖这个值。所以无论它存储在什么地方,它都必须是一个定长的值,它应该被变成UInt64型。 
除此之外,所有的UInt值都可以换成VInt型以去掉限制。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值