version: Lucene_3.5

了解Lucene的核心,我是从源代码对比Lucene的文件格式(File Formats)入手的。最核心的参考资料为《Lucene原理与源代码分析完整版》,尽管其版本为3.0,但是对于3.5的版本仍具有非常重要的参考价值。

分析建立硬盘索引的过程:


1、write.lock文件的生成及作用

在lucene_test目录下生成的第一个文件就是write.lock文件。这个文件在IndexWriter的构造器中执行writeLock = directory.makeLock(WRITE_LOCK_NAME);语句时生成。

这个文件是个临时文件,在索引创建结束后会被删除。如果我们在lucene_test的目录中看到这个文件,表明此时有writer正在修改索引数据(添加或者删除document)。这个锁文件保证了在任意时刻,最多只有一个writer在修改索引数据。

如果试图在同一个索引目录下生成多个IndexWriter对象,则会报AlreadySetException异常。

2、fdt文件和fdx文件的生成。

lucene中,fdt与fdx文件都是在FieldsWriter中生成的。对于每个Document,解析其Fields中的内容后(这个解析过程是比较复杂的,包括分词等操作,后面详细讨论),把Document中的Field作为正向信息原封不动地存储到文件中(一般用于内容的展示,不参与打分排序)。

fdt(FieldData)文件存储Field数据,fdx(FieldIndex)文件存储Field索引。如果把一本书拆成目录和正文两部分,那么fdt文件就是正文,fdx文件就是目录。这样就使得我们能够快捷地读取Document中的内容。从这里也可以猜测,对fdt文件的读取一定是随机的,可以定位的,用到了RandomAccessFile类(顺便说一下RandomAccess类还可以实现文件下载的断点续传功能)。

3、tis和tii文件的生成<反向信息>

IndexWriter时,存储在绥存中的词信息就需要flush到硬盘上了。在这个过程中,tis和tii文件会被创建。tis和tii文件都是在TermInfosWriter类的构造函数中生成的。

tis和tii两个文件存储Term,即词信息。与fdt文件和fdx文件类似,tis文件存储term内容,tii文件是tis文件的索引。

4、frq文件的生成<反向信息>

frq文件存储倒排表信息,即每个term在哪些文档中出现,并且存term在每个文档出现的次数。此文件在FormatPostingsDocsWriter的构造函数中生成。

5、prx文件的生成<反向信息>

prx文件存储的是每个term在出现文档中的位置信息。

由FormatPostingsPositionsWriter的构造函数生成。需要注意的是,如果所有的Field都需要不保存词的位置信息,则此文件将不存在。

6、norm文件的生成

norm文件保存所有的标准化因子。该文件在NormsWriter的flush函数中生成。对于标准化因子,乍一看不好理解,通俗而不全面的理解就是“文档加权”(也包含长文档的降权)。标准化因子由三部分组成:document boost、field boost、lengthNorm(field)。关于norm的通俗解释可参见: 博客。

7、fnm文件的生成

fnm文件存储的信息非常简单明了,就是Field的名字及field的结构信息。该文件在DocFieldProcessor的flush方法中生成。

8、segments_N文件的生成

  segments_N文件是索引目录中segments_*文件的总称。此文件存储了索引的段信息,即索引包含了多少段,每个段的段名、段的大小、段包含Document数目等信息。该文件在SegmentInfos类的write方法中生成。

9、Segments.gen文件的生成

Segments.gen文件在SegmentInfos类的finishCommit方法中生成。Segments.gen文件也存储了段信息。其作用在于辅助index打开segments_N文件。


以上就是程序执行过程中依次生成的索引文件,这些文件共同组成了一个完整的索引。当然,如果有一些特殊的需求,比如高亮显示、模糊查询,那么需要设置Field.TermVector参数,那样的话,索引文件的成员又会增加三个tvd、tvf、tvx。当数据量特别大时,索引又会生成cfs、cfe文件。总之,在lucene3.5中,围绕着索引的总共有17种文件。其中,最核心的是frq文件,即倒排表。它是整个索引的灵魂之所在。
在建立索引的过程中,词信息是由BytePool、CharPool、IntPool三个缓存来进行存储。当缓存满了,则flush到硬盘中。

以上就是我所理解到的Lucene建立索引的过程。