lucene搜索引擎技术的分析与整理(lucene文档结构)

Lucene文档结构 
Lucene 中最基础的概念是索引( index ),文档( document .,域( field )和项( term )。
索引包含了一个文档的序列。
·     文档是一些域的序列。
·     域是一些项的序列。
·     项就是一个字串。
存在于不同域中的同一个字串被认为是不同的项。因此项实际是用一对字串表示的,第一个字串是域名,第二个是域中的字串。
4.1.   Lucene概念详细介绍
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)
  最基本的数据类型就是字节( 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 
 0 
 00000000 
  1 
 00000001 
  2 
 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 
 ... 
这种编码提供了一种在高效率解码时压缩数据的方法。  
Lucene 输出 UNICODE 字符序列,使用标准 UTF-8 编码。
String 
Lucene 输出由 VINT 和字符串组成的字串, VINT 表示字串长,字符串紧接其后。
String --> VInt, Chars 
 
  索引中活动的段存储在 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 
剩下的文件是每段中包含的文件,因此由后缀来区分。
域( Field
域集合信息( Field Info  
所有域名都存储在这个文件的域集合信息中,这个文件以后缀 .fnm 结尾。

FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount 
FieldsCount --> VInt 
FieldName --> String 
FieldBits --> Byte 
目前情况下, FieldBits 只有使用低位,对于已索引的域值为 1 ,对未索引的域值为 0
文件中的域根据它们的次序编号。因此域 0 是文件中的第一个域,域 1 是接下来的,等等。这个和文档号的编号方式相同。  
域值存储表使用两个文件表示:
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 表示未分解过。÷
  项字典用以下两个文件表示:
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 ,对于文件中第一个项)。  
  .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 
 .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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值