在前面的几篇关于lucene的文章中,我已经简要说明了如何利用lucene进行分词、索引和搜索。最近大部分时间耗在查资料上,看得比较多比较杂但是一贯的不够深入,还好多数都是不会影响编程实践的概念性的东西。有时候我自己也感觉到有心无力,太关注那些表面的繁文缛节性的东西有让人失掉好奇、激情和勤奋实践的风险,毕竟我个人需要专心专注的事情是解决问题而不是多知道几个概念和专业名词,要先做出东西来,虽然这样显得不是很专业。本文简单补充记录一下对于lucene创建索引有用的几个参数以及索引文件中的常见的几种格式的感性认识和总结,希望对你也有帮助。
一、提高索引速度几个有用的参数
在索引算法确定的情况下,最为影响lucene索引速度的主要是三个参数,即IndexWriter中的 mergeFactor, maxMergeDocs和RAMBufferSizeMB 。这些参数主要就是控制内外存交换和索引合并频率,从而达到提高索引速度的目的,当然这几个参数的具体设定和机器的硬件条件也密不可分。
1、mergeFactor
mergeFactor就是所谓的“合并因子”,它的作用主要是用于子索引(segment)合并的。 如你所知,lucene中索引总体上是这样进行的:索引先写入内存,触发一定限制条件后写入硬盘,生成一个独立的子索引(segment)。通常情况下,多个子索引在优化(optimize())后会合并成一个索引,否则子索引会很多,影响检索速度,而且占用的磁盘空间可能会非常大。mergeFactor这个参数就是控制当硬盘中有多少个子索引segments时,lucene就需要把这些子索引合并成一个较大一点的索引。合并的内部实现细节我也不是很清楚,但是lucene 中默认索引合并机制并不是两两合并,通常都是多个segment一次合并成一个较大索引,所以mergeFactor越大耗费内存越多,索引速度也会快些。
IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);Console.WriteLine(writer.GetMergeFactor());//mergeFactor默认是10writer.SetMergeFactor(30);Console.WriteLine(writer.GetMergeFactor());//设置后,当前是30
mergeFactor默认值是10,您可以自己设置合理的合并因子的值来加快构造索引。
2、maxMergeDocs
合并因子mergeFactor是从segment优化性能入手,而maxMergeDocs,看命名就知道是从构成子索引(segment)的文档(document)着手提升性能。 maxMergeDocs参数决定写入内存索引文档(document)的个数,到达该数目后就把该内存索引写入硬盘,生成一个新的子索引segment文件,所以该参数也就相当于一个内存buffer,一般来说越大索引速度越快。
需要注意的是,maxBufferedDocs这个参数默认是disabled的,因为lucene中还用另外一个参数(RAMBufferSizeMB)控制这个bufffer的索引文档个数。其实maxBufferedDocs和RAMBufferSizeMB这两个参数是可以一起使用的,一起使用时只要有一个触发条件满足就写入硬盘,生成一个新的子索引segment文件。
IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);Console.WriteLine(writer.GetMaxMergeDocs());//MaxMergeDocs默认值是2147483647 (也即int.MaxValue)writer.SetMaxMergeDocs(1024);Console.WriteLine(writer.GetMaxMergeDocs());//设置后,当前是1024
maxMergeDocs默认值是常量int.MaxValue(2147483647)。
3、RAMBufferSizeMB
如你所知,这个参数作用类似于maxMergeDocs,控制用于缓存索引文档的内存上限。如果buffer的索引文档个数到达该上限就写入硬盘。一般来说该参数越大,占用内存越大,索引速度也就越快。
IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);Console.WriteLine(writer.GetRAMBufferSizeMB());//RAMBufferSizeMB默认值是16 writer.SetRAMBufferSizeMB(1024);Console.WriteLine(writer.GetRAMBufferSizeMB());//设置后,当前是1024
RAMBufferSizeMB默认值是16.
小结:通过上述分析说明,我们知道,合理设置三个参数的值,可以充分利用内存(理论上,参数值越大,内存利用越充分,但是必须和实际的机器性能相结合),避免频繁的IO操作,提升索引速度。
二、关于索引文件的几种常见格式
这里我主要参考了觉先的这一篇和这一篇非常耐心详细的两篇好文章。虽然收藏已久,但是直到现在自己还没有完全搞明白各个文件之间的关系。现在看来,依然醍醐灌顶很有收获。态度决定一切,有时间我会重新写一篇更详细透彻的学习笔记。下面重点记录一下对我自己的实际编程有帮助的几个文件格式。
1、.gen格式和segments_N
每个segment代表lucene的一个完整索引段,建立索引后必须存在的一个文件。一个索引(Index)可以同时存在多个segments_N。当我们要打开一个索引的时候,我们必须要选择一个segments_N文件来打开。在打开索引选择某个segments_N文件时,segments.gen文件和segments_N的N(Generation)的确定就有密切关系(具体逻辑可以参考这篇的4.1.1)。
2、.cfs格式
即复合索引文件格式。我们知道,索引的内容可能非常大,文件数量也可能非常多。如果遇到这种情况,系统打开文件的数量将很大,会极大地耗费系统资源。因此,lucene提供了一个单文件索引格式,也就是所谓的复合索引格式。使用复合索引格式存储Document内容时,只需要在初始化完成一个IndexWriter对象后,使用SetUseCompoundFile(boolean)方法,在设置UseCompoundFile为true后,就会有这个文件。
IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);Console.WriteLine(writer.GetUseCompoundFile());//默认为truewriter.SetUseCompoundFile(false);Console.WriteLine(writer.GetUseCompoundFile());
默认情况下,IndexWriter将UseCompoundFile置为True。
3、.lock格式
顾名思义,.lock就是锁文件类型了。对于普通优化后的索引文件,这个锁文件是看不到的。当我们通过IndexWriter或者IndexModifier对索引文件进行插入、修改或者删除操作的时候,都会生成一个.lock的锁文件。在lucene旧版本的类库中,通过多线程进行索引更改等操作,很容易发生异常,通常情况下都是由于该锁文件。提到了锁机制,我们有必要了解一下lucene的并发性规则:
操作 | 是否允许 |
对同一个索引运行多个并行的搜索进程 | 是 |
对一个正在生成、被优化或正在与另一索引合并的索引运行多个并行的搜索进程,或该索引正在进行删除、更新文档等操作时,对索引运行多个并行的搜索进程 | 是 |
对同一个索引用多个IndexWriter对象执行添加、更新文档的操作 | 否 |
当一个从索引中删除文档的IndexReader对象没有成功关闭时,打开一个IndexWriter对象用于在这个索引中添加新的文档 | 否 |
IndexWriter对象向索引中添加新文档后,未成功关闭;在此之后,打开一个IndexReader对象用于从这个索引中删除文档 | 否 |
我们可以看到这种并发性规则对于搜索是毫无限制的,但是索引的其他操作可能会对搜索产生影响,比如更新后还没有优化的索引可能影响搜索速度,搜索的准确性也不可靠。好在我们的实际项目中都会有一定的策略来使用索引,比如相同的索引复制两份,一份专门用来搜索,一份用来增删改和优化,然后定时切换。
3、.fnm格式
包含 Document中所有Field名称。
4、.fdx和.fdt格式
.fdt文件用于存储具有 Field.Store.YES属性的field的数据的相关信息。而.fdx类型文件则是一个索引,用于存储域的信息。
5、.tii和.tis格式
.tii存储分词后term的索引文件,标明了每个.tis文件中词条的位置。
6、deletable格式
在lucene的索引中,所有的文档被删除后并不是立刻从索引中去除,而是留待下次合并索引或对索引进行优化时才真正删除。这种功能是通过deletable文件实现的。所有的文档在被删除后,会首先在deletable文件中留一个记录,要真正删除时,才将索引除去。
最后附上一张流传于网上的简明图片说明一下常见的索引及其文件格式的关系:
其他参考文章:
http://lucene.apache.org/java/2_9_2/fileformats.html