lucene索引优化
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这篇文章主要介绍了如何提高Lucene的索引速度。
介绍的大部分思路都是很容易尝试的,当然另外一部分可能会加大你程序的复杂度。
所以请确认索引速度确实很慢,而且很慢的原因确实是因为Lucene自身而造成的。
推荐姐妹篇:如何提高和优化Lucene搜索速度
• 确认你在使用最新的Lucene版本。
• 尽量使用本地文件系统
远程文件系统一般来说都会降低索引速度。
如果索引必须分布在远程服务器,请尝试先在本地生成索引,然后分发到远程服务器上。
• 使用更快的硬件设备,特别是更快的IO设备
• 在索引期间复用单一的IndexWriter实例
• 使用按照内存消耗Flush代替根据文档数量Flush
在Lucene 2.2之前的版本,可以在每次添加文档后调用ramSizeInBytes方法,当索引消耗过多的内存时,然后在调用flush()方法。
这样做在索引大量小文档或者文档大小不定的情况下尤为有效。
你必须先把maxBufferedDocs参数设置足够大,以防止writer基于文档数量flush。
但是注意,别把这个值设置的太大,否则你将遭遇Lucene-845号BUG。
不过这个BUG已经在2.3版本中得到解决。
在Lucene2.3之后的版本。
IndexWriter可以自动的根据内存消耗调用flush()。
你可以通过writer.setRAMBufferSizeMB()来设置缓存大小。
当你打算按照内存大小flush后,确保没有在别的地方设置MaxBufferedDocs值。
否则flush条件将变的不确定(谁先符合条件就按照谁)。
• 在你能承受的范围内使用更多的内存
在flush前使用更多的内存意味着Lucene将在索引时生成更大的segment,也意味着合并次数也随之减少。
在Lucene-843中测试,大概48MB内存可能是一个比较合适的值。
但是,你的程序可能会是另外一个值。
这跟不同的机器也有一定的关系,请自己多加测试,选择一个权衡值。
• 关闭复合文件格式
调用setUseCompoundFile(false)可以关闭复合文件选项。
生成复合文件将消耗更多的时间(经过Lucene-888测试,大概会增加7%-33%的时间)。
但是请注意,这样做将大大的增加搜索和索引使用的文件句柄的数量。
如果合并因子也很大的话,你可能会出现用光文件句柄的情况。
• 重用Document和Field实例
在lucene 2.3中,新增了一个叫setValue的方法,可以允许你改变字段的值。
这样的好处是你可以在整个索引进程中复用一个Filed实例。
这将极大的减少GC负担。
最好创建一个单一的Document实例,然后添加你想要的字段到文档中。
同时复用添加到文档的Field实例,通用调用相应的SetValue方法改变相应的字段的值。
然后重新将Document添加到索引中。
注意:你不能在一个文档中多个字段共用一个Field实例,在文档添加到索引之前,Field的值都不应该改变。
也就是说如果你有3个字段,你必须创建3个Field 实例,然后再之后的Document添加过程中复用它们。
• 在你的分析器Analyzer中使用一个单一的Token实例
在分析器中共享一个单一的token实例也将缓解GC的压力。
• 在Token中使用char[]接口来代替String接口来表示数据
在Lucene 2.3中,Token可以使用char数组来表示他的数据。
这样可以避免构建字符串以及GC回收字符串的消耗。
通过配合使用单一Token实例和使用
char[]接口你可以避免创建新的对象。
• 设置autoCommit为false
在Lucene 2.3中对拥有存储字段和Term向量的文档进行了大量的优化,以节省大索引合并的时间。
你可以将单一复用的IndexWriter实例的autoCommit设置为false来见证这些优化带来的好处。
注意这样做将导致searcher在IndexWriter关闭之前不会看到任何索引的更新。
如果你认为这个对你很重要,你可以继续将autoCommit设置为true,或者周期性的打开和关闭你的writer。
• 如果你要索引很多小文本字段,如果没有特别需求,建议你将这些小文本字段合并为一个大的contents字段,然后只索引contents。
(当然你也可以继续存储那些字段)
• 加大mergeFactor合并因子,但不是越大越好
大的合并因子将延迟segment的合并时间,这样做可以提高索引速度,因为合并是索引很耗时的一个部分。
但是,这样做将降低你的搜索速度。
同时,你有可能会用光你的文件句柄如果你把合并因子设置的太大。
值太大了设置可能降低索引速度,因为这意味着将同时合并更多的segment,将大大的增加硬盘的负担。
• 关闭所有你实际上没有使用的功能
如果你存储了字段,但是在查询时根本没有用到它们,那么别存储它们。
同样Term向量也是如此。
如果你索引很多的字段,关闭这些字段的不必要的特性将
对索引速度提升产生很大的帮助。
• 使用一个更快的分析器
有时间分析文档将消耗很长的时间。
举例来说,StandardAnalyzer就比较耗时,尤其在Lucene 2.3版本之前。
你可以尝试使用一个更简单更快但是符合你需求的分析器。
• 加速文档的构建时间
在通常的情况下,文档的数据来源可能是外部(比如数据库,文件系统,蜘蛛从网站上的抓取等),这些通常都比较耗时,尽量优化获取它们的性能。
• 在你真的需要之前不要随意的优化optimize索引(只有在需要更快的搜索速度的时候)
• 在多线程中共享一个IndexWriter
最新的硬件都是适合高并发的(多核CPU,多通道内存构架等),所以使用多线程添加文档将会带来不小的性能提升。
就算是一台很老的机器,并发添加文档都将更好的利用IO和CPU。
多测试并发的线程数目,获得一个临界最优值。
• 将文档分组在不同的机器上索引然后再合并
如果你有大量的文本文档需要索引,你可以把你的文档分为若干组,在若干台机器上分别索引不同的组,然后利用writer.addIndexesNoOptimize来将它们合并到最终的一个索引文件中。
• 运行性能测试程序
如果以上的建议都没有发生效果。
建议你运行下性能检测程序。
找出你的程序中哪个部分比较耗时。
这通常会给你想不到的惊喜。
当你取回文档时,使用FieldSelector仔细的选择哪些字段需要获取,如何获取。
不要获取多于你需要的hits
获取更多的搜索结果将会降低搜索速度。
有两个原因:其一,search方
法在返回Hits对象时,如果超过100个hits,lucene将在内部自动重
新执行搜索。
解决方案:使用返回HitCollector的Search方法。
其二,搜索结果可能分布在硬盘的不同地方,获取他们可能需要很多的IO操作。
这个是很难避免的,除非索引比较小,可以直接缓存到内存当中。
如果
你不需要完整的文档对象,你只需要其中的一个很小的字段,你可以使
用FieldCache类来缓存它,从而达到快速访问的效果。
∙当使用 fuzzy 查询时设置一个较小的比较长度(prefixLength)
Fuzzy查询执行CPU密集型字符串比较,尽量避免将用户查询的Term与所有的 Term进行比较。
你可以设置只比较以前N个字符开头的Term。
prefixLength在QueryParser以及FuzzyQuery中可以设置。
默认值为0,将比较所有的Term。
∙考虑使用filters
有时候我们的查询将限制部分索引中的记录,这时候使用一个经过缓存了的bit set filter将比使用查询子句更有效,尤其在一个大索引中。
过滤器经常用在查询分类结果上。
它可以用查询子句限制来替换,区别在于使用Query将影响文档的得分,而Filter不会。