NLucene研究系列(3)-基本机制
Data Flow
NLucene内部的数据流图如下所示,共包含了4种数据流格式:分别是文本流、Token流、字节流与查询语句对象流。文本流表示了对于索引目标和交互控制的抽象,即用文本流表示了将要索引的文件,用文本流向用户输出信息;在实际的实现中,NLucene中的文本流采用了UCS-2作为编码,以达到适应多种语言文字的处理的目的。Token流是NLucene内部所使用的概念,是对传统文字中的词的概念的抽象,也是NLucene在建立索引时直接处理的最小单位。字节流则是对文件抽象的直接操作的体现,通过固定长度的字节(NLucene定义为8比特位长,后面文件格式将详细叙述)流的处理,将文件操作解脱出来,也做到了与平台文件系统的无关性。查询语句对象流则是仅仅在查询语句解析时用到的概念,它对查询语句抽象,通过类的继承结构反映查询语句的结构,将之传送到查找逻辑来进行查找的操作。
Index File Formats
NLucene中的索引信息以文件形式保存。其逻辑结构如上图所示:一个Index可以分为若干个Segment(Segment可以合并,详见后文),每个Segment由若干个Document组成,然后再进一步分成Filed, Term, 从而形成了如上的逻辑构图。为了帮助理解,我们可以用熟悉的数据库系统作个隐喻,Segment相当于Database, Document对应于Table, 而Filed就相当于Table中的Column, Term就是Row中具体的内容。NLucene采用了自定义的数据类型将这些索引文件存储到一些列的文件中。由于这种基于bit的数据存储格式,使得索引文件具有良好的跨平台性。
需要注意的是,索引结构不但能建立在文件系统(FSDirectory)中也可以建立在内存(RAMDirectory)中。
Defined Data Type
在介绍索引文件之前,先描述一下几个文件格式中常用的数据类型:
Ø VInt, 可变长度的整数,最小一个字节,可以是2-4个字节,如果一个字节表示不了的话。不过通常是一个字节就够了;
Ø Vlong,可变长度的长整数,最小一个字节,可以是2-8个字节,如果一个字节表示不了的话。不过通常是一个字节就够了;
Ø VString,由于Lucene的开发语言java中的字符串是没有像C里面一样的’\0’的结束符的,所以在文件中记录一个字符串时,在字符串前放一个VInt表示字符串的长度;
Ø UInt32,4个字节的整数;
Ø UInt64(Long),8个字节的整数。
详细说明见下表:
Index File Composing
NLucene的索引文件存在一个索引目录中。文件共有10种:*.f(n), *.fdt, *.fdx, *.fnm, *.frq, *.prx, *.tii, *.tis, deletable, seqments。下面分别描述:
Ø segments文件,用来表示索引文件的名字和Document的个数。在SegmentInfos描述,参见write()文件头中的第1个4Byte是SegmentName,在NLucene中,SegmentName是一个16进制的数字,是上面的如*.fnm中的*部分,每新增加一个Document,SegmentName会加1,所以此部分的值会比实际的SegmentName大1。文件头中的第2个4Byte是索引文件的个数,Lucene支持在一个目录中存放多个索引文件。文件体中 是一个可重复的部分,重复的次数由文件头中的第2部分的大小决定。可重复的部分包括2个部分:SegmentName和该索引文件中包含的Document个数。(从这里可以看出,在Lucene中,单个索引文件最多可以包含2的32方个文件(4个byte);
Ø *.frm文件,用来保存FieldName,注意,此文件只保存非切分部分的Field,如通过Filed.text()方法进行切分后的Field保存在*.tii, *.tis中。
具体格式如下:(在FieldInfos描述,参见write())
文件头中的FieldNum代表索引的Field的个数。文件体中描述每个Field的信息,个数与文件体中的FieldNum相同。每个Field的信息包括2个部分:FieldName,索引的Field的名字,Flag表示该Field是否是索引的(indexed)。0×00表示未索引,0×01表示索引。
Ø *.fdt文件,用于存放Field的值,每个Document是连续存放的,每个Document内部的格式如下:(参看FieldsWriter文件的AddDocument()函数)头部中的FieldNum是该Document中选择了存储的Field的个数(field.isStroed()==true),内容体中每个Filed中包括3个部分。
Pos:该Field在Document的顺序,是第几个Field
Flag:该Field是否是一个Token(field.isToken()==true)
Value:该Field的值
Ø *.fdx文件,用于存放每个Document在fdt文件中的偏移。
每个Document中记录的是一个Long型的整数,代表*.fdt文件中每个Document的偏移(起点-1)
Ø *.tis文件,用于存放切分过的Field中的值。(参看2,fnm文件)文件格式参看TermInfosWriter文件中的add()函数)文件头中的TermNum是一个4byte的Int,代表Term的个文件体是每个Term的重复。每个Term包括7个域。
Start:该Term的偏移
Content:该Term的值
FieldPos:该Term出现的顺序,即是第几个Field
Freq:该Term出现的频率
FreqPointer:Rreq在*.frq文件中的偏移
ProxPointer:Prox在*.prx文件中的偏移
IndexPointer:Index在*.tii文件中的偏移(我不敢确定),该项是可选项,只在isIndex==true是出现。(不明白这个的意思,isIndex指什么)也可以参看SegmentTermEnum中的next()函数,这是一个读单个term的函数。
Ø deletable文件,用来存放被删除的文件名。文件格式参看IndexWriter中的readDeleteableFiles()函数)文件体中 是一个4byte的整数,代表被删除的文件个数文件体中是一组被删除的文件名。还有*.f(n)是存放Norm的文件,*.tii是与*.tis相对的,*.frq(存放词频的文件),*.prx(存放词频的位置的文件,与*.frq文件联合使用。