一、索引是LUCENE最重要的一个过程,通过IndexWriter的addDocument接口,可以将构建的Document加入索引。
二、IndexWriter的addDocument方法首先创建一个DocumentWriter对象,接着为Segment命名,然后调用DocumentWriter的addDocument()方法向索引中增加文档,最后将Segment的信息保存,如果有多个segment则判断是否需要合并,如果需要则合并。一个索引可能有多个segment,每个segment里有许多Document。每个segment的前缀生成方式是将segmentInfos.couter值(当前segment中总共的文档数量)先加1,再转移成36进制,然后在前面加一个下划线就成为了segment的名称。
三、DocumentWriter的addDocument方法完成实际的数据存储工作。
1)第一步,首先初始化一个FieldInfos对象,然后将当前Document传入其中,把所有Field的信息(注意不是内容)写入.fnm文件(在FieldInfos.write完成)。
(A)在写入工作之前使用FieldInfos.add方法将当前的Document加入到fieldInfos对象中。
(B)FieldInfos.write实现:
public void write(Diretory d,String name) throws IOException{
IndexOutput output=d.createOutput(name);
try{
//写入fields信息
write(output);
}finally{
//关闭输出流
output.close();
}
}
public void write(IndexOutput output) throws IOException{
//先写入Fields的数量
output.writerVInt(size());
//对所有Fields进行循环
for (int i=0;i<size();i++) {
FieldInfo fi=fieldInfo(i);
byte bits=Ox0;
if (fi.isIndexed) bits|=IS_INDEXED;
if (fi.storeTermVector) bits|=STORE_TERMVECTOR;
if (fi.storePositionWithTermVector) bits|=STORE_POSITIONS_WITH_TERMVECTOR;
if (fi.storeOffsetWithTermVector) bits|=STORE_OFFSET_WITH_TERMVECTOR;
if (fi.omitNorms) bits|=OMIT_NORMS;
output.writeString(fi.name);
output.writeByte(bits);
}
}
2)第二步,使用fieldWriter.addDocument方法将Document中的各个Field信息写入.fdt文件和.fdx文件。
(A)首先,向.fdx写入当前Document的位置信息
(B)接着,将需要存储的field的数量写入.fdt中
(C)遍历field。
a)如果当前field需要存储,向.fdt中写入field的编号
b)使用位运算来表示当前field的各种属性。向.fdt中写入当前field属性
c)如果field需要压缩,则进行压缩,将压缩后的field数据长度写入.fdt,之后,向.fdt中写入field的值。
d)如果不需要压缩,如果field是二进制类型,则将field数据长度写入.fdt,之后,向.fdt中写入field的值;如果不是二进制类型,直接向.fdt写入field的值
3)第三步,初始化hashtable和其它一些长度数据。
4)调用invertDocument进行文件倒排,有2个主要部分
A)对所有需要加入索引的field进行遍历。对于那些不需要分词的field,就将其整个field的数据做为一个大词条,放入postingTable(一个hashtable)中去(使用adddPostion方法加入名称、值、频率、位置,如果要求还要加上词条向量)。
B)对于需要分词的field,则调用底层分词接口进行分词,然后将每个分出来的词都放入到postingTable中去。
5)第四步,将postingtable进行转化成posting数组进行排序。使所有词条按字典顺序排列
6)第五步,将排列好的词条信息写入.tii和.tis文件,将频率和位置信息.frq和.prx文件
A)lucene索引中对词条的保存并非完整的词条本身,如"smi smith steve" 保存为"smi" "th" "teve"词条片段。
四、索引文件格式
1)segment
每个segment代表lucene的一个完整索引段。在一个索引中,会包含多个segment。每个segment都有统一的前缀,这个前缀是根据当前索引的Document的数量而确立的。一个完整的索引,只有一个segments文件,记录当前索引中所有segment的信息。
2).fnm
.fnm格式的文件中包含了Document中的所有field名称。
3).fdx和.fdt格式
.fdt用于存储具有Store.YES属性的Field的数据。而.fdx类型文件则是一个索引,用于存储Document在.fdt中的位置。
4).tii和.tis格式
.tii用于存储分词后的词条,而.tii是它的索引文件,标明了每个.tis文件中的词条的位置。
五、复合索引格式.cfs
在IndexWriter中有一个属性:useCompoundFile,默认值为True,在初始化完一个IndexWriter对象后,使用setUseCompoundFile(boolean)方法将useCompoundFile的属性值设为True