您的位置:首页 > 其它

lucene索引结构的整理

2011-04-10 13:12 260 查看
 

倒排索引结构,示例如下:

 
设有
2
篇文章:

文章1的内容为:Tom lives in
Guangzhou,I live in Guangzhou too.
文章2的内容为:He once lived in
Shanghai.
 
分词:英文以空格分隔,中文根据基础词典和扩展词典分隔为字和词。

去停用词、标点符号、大小写转换等,由
Analyzer
完成。

文章1的所有关键词为:[tom] [live]
[guangzhou] [i] [live] [guangzhou]
文章2的所有关键词为:[he] [live]
[shanghai]
 
建立倒排索引:

Term
文章号(出现频率)
出现位置
guangzhou
1[2]
3,6
he
2[1]
2
i
1[1]
4
live
1[2],2[1]
2,5,2
shanghai
2[1]
3
tom
1[1]
1
 
lucene将上面三列分别作为词典文件(Term
Dictionary)、频率文件(frequencies)、位置文件
(positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。Lucene中使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。
 
压缩:
term
压缩:

关键词压缩为<前缀长度,后缀>。例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>
数字压缩:

数字只保存与上一个值的差值。例如当前文章号是16389,上一文章号是16382,压缩后保存7。
 
 
lucene
建立索引的流程:

指定生成
index
的目录;

创建
IndexWriter
对象
:初始化
segments
文件

IndexWriter writer = new IndexWriter(index_dir,new
StandardAnalyzer(),false);
第一个参数:生成
index
的目录;

第二个参数:生成索引所用的分析器;
第三个参数:
true
为重新索引,
false
为增量索引。

生成一个
document
对象


Document doc = new Document();
doc.add(new
Field(name,value,Field.Store.YES,Field.Index,TOKENIZED));
域的属性:是否
store
,是否
index
,是否切词


doc
加入
IndexWriter
对象


 
writer.add(doc);
优化并关闭
IndexWriter
对象


writer.Optimize(); 
//
将所有的
segments
合并为一个

writer.close();
 
 
lucene
索引文件结构:

逻辑结构:

 
每当往
index
中加入一个
doc
,都会新生成一个
segment
保存这个
doc
,通过判断合并
segment


最后通过优化索引的命令,将所有的
segment
合并为一个
index
。一般以一个
doc
为单位往
index

添加记录,一个
doc
有几个
field
组成,每个
field
保存不同的信息,可以指定在某个域搜索。

每个域由很多
term
组成。

 
物理结构:

 
segments:

s
egments
文件的结构是:

Format+version+counter+Count+<si0.name+si0.docCount>+<si1.name+si1.docCount>…+<sin.name+sin.docCount>
即:索引文件格式
+
index
修改次数
+segment
总数
+
给新生成的
segment
取一个随机的名字

+<segment0
名字
+segment0
文档数
>+<segment1
名字
+segment1
文档数
>

deletable:

lock:

index.lock
文件:

表示有进程在向索引中加入文档,或者是从索引中删除文档。这个文件防止很多文件同时修改一个索引。
segment:
count
:要删除的文件总数;

文件名:要删除的文件名字

域集合信息(
.fnm
文件):

.fnm
文件的结构是:
size+<fi0.name+bits0>+<fi1.name+bits1>+...+<fin.name+bitsn>

域值存储表:
.fdx
文件:

.fdt
文件:

标准化因子(
.nrm
文件):

项字典:

.tis
文件:

size:doc

term
的总数

indexInterval
:索引间隔,默认值为
128,
这个参数决定写入
tii
文件中的
term
的数量。

skipInterbal
:跳跃间隔,默认值为
16


start
:当前
term
与前一个
term
相同的前缀字符串的长度。

length
:去除了当前
term
与前一
term
共享的前缀字符串后余下的字符串长度。

text
:余下的字符串值。

fieldNumber
:其所在
field
的编号。

docFreq
:出现这个
term

doc
的数量。

freqpointerDelta:
决定了在
.frq
文件中当前词
frq
的位置。即相对于前一个词的数据的位置偏移量(如果是
0
则表示是在文件中的第一个词条)。
 

proxPointerDelta:
决定了在
.prx
文件中当前词
prox
的位置。即相对于前一个词的数据的位置偏移量(如果是
0
则表示是在文件中的第一个词条)。
 

skipOffset
:决定了在
.frq
文件里当前词条
SkipData
的位置。它是
TermFreq
的数据长度,
SkipDelta
只在
DocFreq
不小于
SkipInterval
时才存储。

.tii
文件:

项频数(
.frq
文件)

是差值?

项位置(
.prx
文件)


被删除文档(
.del
文件)


即:该
doc

field
的总数
+<

0
名字
+

0
基本信息
>+<

1
名字
+

1
基本信息
>

基本信息
:低第一位
1
表示已经索引,
0
表示未索引。低第二位
1
表示有
term
矢量,
0
表示没有
term
矢量

用于在域信息文件中定位一个特定文档的域信息。
文档
n
的域信息是第
n*8
开始的
Uint64


.fdt
文件的结构是:

storecount+<field0.number+bits0+field0.value>+<field1.number+bits1+field1.value>+…+<fieldn.number+bitsn+fieldn.value>

:
记录这个
doc
中需要存储的
filed
总数
+<

0
编号
+

0
属性(是否分词、是否包括
2
进制、是否压缩)
+
记录
filed
的具体内容
>

对每个
field
,都会生成一个
.f
文件,其中记录了每个
doc
在命中该域时乘的因子的大小。

.f
的文件结构是:
doc0.filed0.norm+
doc1.field0.norm+…+docn.field0.norm

每个
doc
都会使用哈希表
postingTable
来保存该
doc
所包含的
term
的信息

这个哈希表的
key

term
,值是
posting

posting
是实际记录一个
term
在这个
doc
中信息的类。

Posting
主要包含以下信息:

term
:一个
term
对象,表明这个
posting
是属于哪个
term
的;

freq:
记录这个
term

doc
中出现的频率;

positions[]:
记录这个
term
每次出现在
doc
的哪个位置;

offset
:保存与
termvector
相关的内容


 

这个
postingTable
写入文件


.tis
文件的结构:
FORMAT+size+indexInterval+skipInterbal+<term0.start+term0.length+term0.text+term0.FieldNumber+term0.DocFreq+term0.FreqpointerDelta+term0.proxPointerDelta+term0.skipOffset>+…+<termn.start+termn.length+termn.text+termn.FieldNumber+termn.DocFreq+termn.FreqpointerDelta+termn.proxPointerDelta+termn.skipOffset
>

即:
假设前一个
term

bit
,当前
term

bike
,则
start=2

length=2

text==

ke
”。

.tis
文件的索引,记录了
.tis
文件中部分
term
及在
.tis
文件中的位置,默认为
term
总数的
1/128

.frq
文件的结构

term0.freq+term1.freq+…+termn.freq

.prx
文件的结构

term0.position[0]+(term0.position[1]-term0.position[0])+
(term0.position[2]-term0.position[1])+…+(term0.position[n-1]-term0.position[n-2])+….(termn.position[n-1]-termn.position[n-2])

其中
term.position

表示该
term

field
中出现第
n+1
次时的偏移位置。

要删除的文件保存在
deletable
文件中,这个文件记录以下数据:

删除文件所采用的策略是
:当每次合并时尝试删除
deletable
中所标识的所有文件,有些文件可能正在被使用而无法删除,生成一个新的
deletable
文件取代原来的文件,记录新增的要删除的文件和保留那些没能够删除的文件。

segment
合并
:每添加一个文档,都会生成一个
segment
,再合并
segment


判断是否合并的规则:
设置一个
targetMergeDocs
,第一次合并时值为
10
,接下来依次×
10
,即第
2
次合并时值为
100
,第
3
次合并时值为
1000
,依次类推。每次判断时,读取一个
segment

doc
数,这时有
3
种可能。

1.
如果该
segment

doc
数大于等于当前的
targetMergeDocs
,则对该
segment
不进行任何操作;

2.
如小于,则把他的
doc
数和后续那些同样
doc
数小于
targetMergeDocs

segment

doc
数累加,直到累加所得的
doc
数大于或等于
targetMergeDocs
时,把这些参与了累加的
segment
合并成一个新的
segment


3.
如果累加到最后一个
segment
,累加的
doc
数还不大于等于
targetMergeDocs
的话,则不进行合并。

循环这个过程,直到再也不能合并时退出
MaybeMergeSegments()

合并举例

现在按照顺序,有如下几个
segment
,括号内为该
segment

doc
数:

s0(10),
s1(10), s2(10), s3(10), s4(10), s5(10), s6(10), s7(10), s8(10), s9(1), s10(1),
s11(1), s12(1), s13(1), s14(1), s15(1), s16(1), s17(1), s18(1), s19(1)
第一遍合并后:
s0(10),
s1(10), s2(10), s3(10), s4(10), s5(10), s6(10), s7(10), s8(10)
news9(10),s19(1)
第二遍合并后:
news0(100),s19(1)
 
在完成索引最后阶段,有个
Optimize()
函数,这是为了在最后把所有的
segment
全部
合并成最后的一个
segment
文件
,不论是否满足合并的条件。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息