很多人会抱怨 Lucene 在数据量增加到一定规模的时候,性能会出现明显下降,对于并发用户访问的支持能力也比较弱。其实在工程师所遇到的绝大多数环境下 Lucene 的性能问题,往往是因为系统没有经过良好的调优。而非简单的 Lucene 设计缺陷所造成。


当前使用 Lucene 的知名网站包括,Stack Exchange,旗下全球最大的事实性问答网站 StackOverFlow.com .

基于 Lucene 文档 “How to make indexing faster”,我们可以看到如下经验可能可以应用于 Lucene 优化。

确定的确需要进行索引性能调优
很多场景之下,性能问题其实表现为整体数据架构设计的问题,而不仅仅是通过索引所可以解决的。在决定进行索引性能调优之前,可能需要首先判断,是否数据架构上出现了情况。

确定在使用最新版本的Lucene
Lucene也是在不断发展之中。新版本的Lucene通常性能都会有些改善。

使用更快的硬件,例如,改善IO系统性能
通常硬件性能的改善对于系统整体性能提升是立竿见影的。例如,通过SSD硬盘(Solid-State Disk,固态硬盘)取代通常的 SATA 或者 SAS 硬盘,将可以获得明显的系统性能提升。

在建立索引过程中,使用单例的 Writer

基于内存执行 Flush 而不是基于 document count
在 Lucene 2.3 及其以上系统中,IndexWriter可以基于内存执行Flush操作。调用 writer.setRAMBufferSizeMB() 可以设置Buffer大小。

尽量多使用内存
内存越多,Lucene应对海量数据的时候性能明显加强。

关闭复合文件格式(Compound file format)
调用 setUseCompoundFile(false),可以关闭。建立复合文件,将可能使得索引建立时间被拉长,有可能达到7%-33%。而关闭复合文件格式,将可能大大增加文件数量,而由于减少了文件合并操作,索引性能被明显增强。

重用文档与字段实例
这是在 Lucene 2.3 之后才有的一个新技术。在之前如果要修改某个记录,需要删除掉索引中的文档,然后重新添加。而新的方法通过 setValue 实现。这将有助于更有效的减少GC开销而改善性能。

在存储字段数据以及执行 term vectors 的时候,使用同样的字段顺序添加文档
这样将有助于保证合并操作的性能。

在Analyzer中重用单例的Token

在表示 Token 文本内容的时候,使用 char[] API 而不要使用 String API
显然 char 的结构更简单,而操作也更加快速。基于String的性能通常都不怎么好。

在打开 IndexWriter 的时候,设置 autoCommit = false
同传统的数据库操作一样,批量提交事务性能总是比每个操作一个事务的性能能好很多。
同样,对于实时性要求不是很强的系统。通过标记,并定时进行索引和优化,也将比随时进行索引操作性能能改善很多。

不要使用太多的小字段,如果字段过多,尝试将字段合并到一个更大的字段中,以便于查询和索引

适当增加 mergeFactor,但是不要增加的太多。

关闭所有不需要的特性

使用更快的 Analyzer
特别是对于中文分词而言,分词器对于性能的影响更加明显。

加快文档的构造速度
通常,从数据库,文件系统,或者网络爬行过程中,都可能因为上游程序处理的性能而影响 Lucene 文档建立的速度。

除非真的需要改善索引性能,通常不要特别进行优化

对于一个实例的 IndexWriter 可以使用多线程或者并发技术

使用Java Profiler分析 Lucene 和调用程序的性能,并由此改善性能

Index into separate indices then merge.
If you have a very large amount of content to index then you can break your content into N "silos", index each silo on a separate machine, then use the writer.addIndexesNoOptimize to merge them all into one final index.