注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小葫芦君(汉斯的博客)

博客迁移到新博客:https://blog.ssxingshou.com

 
 
 

日志

 
 
关于我

小小葫芦商城,为您提供高品质的商品,一流的产品,一流的包装服务,一流的物流服务,放心购买

网易考拉推荐

如何提高Lucene构建索引的速度  

2013-01-27 10:12:32|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

译自:http://wiki.apache.org/lucene-java/ImproveIndexingSpeed

这里讨论了提高Lucene索引速度的几种方法。

  • 确定你真的需要提高索引速度。
    这里的很多方法很容易尝试,但是有些会增加你程序的复杂性。所以请首先确定索引速度确实太慢,而且速度问题确实是Lucene导致的。
  • 确保你使用的是最新版本的Lucene。
  • 使用本地文件系统。
    远程文件系统索引的速度总是会慢一些。如果你的索引必须放在远程文件系统之上,那么可以考虑先在本地文件系统构建索引,然后再把它复制到远程文件系统。
  • 使用更快的硬件,尤其是更快的IO系统。
    如果可能,使用固态硬盘(solid-state disk,SSD)。这种设备最近价格下降很快,而且在索引无法完全放入操作系统IO缓存的情况下,因为寻道开销很低,可以大幅提高索引速度。
  • 使用单独的写入器,在整个索引会话中复用它。
  • 依照内存使用而不是文档数目来释放缓存。
  • 对于Lucene<=2.2:每添加一个文档后,调用一次writer.ramSizeInBytes()方法,如果写入器占用了太多的内存就调用flush()方法释放缓存。如果你有些很小的文档,或者文档尺寸差异太大,那么这样做就会更好用。首先,你需要把maxBufferedDocs的值设置到很大,大到写入器不会根据文档数目来释放缓存。但是,注意不要设置的太大,否则你就会遇到LUCENE-845问题。这个值大概设为“典型”的释放缓存文档数目的2-3倍就可以了。
    对于Lucene>=2.3:IndexWriter可以自行根据内存使用来释放缓存。调用writer.setRAMBufferSizeMB()方法设置缓存尺寸。确保你没有任何的遗留代码调用setMaxBufferedDocs方法,因为写入器可以根据两种情况一起释放缓存(哪个更早发生)。
  • 使用你可以提供的全部内存。
    在释放缓存之前使用更多的内存,意味着Lucene写入更大的段,意味着延迟合并的发生。LUCENE-843中的测试发现,针对所测内容集合48MB内存是最优值,但是,你的应用可能有不同的最优值。
  • 关闭复合文件格式。
    调用setUseCompoundFile(false)。创建复合文件格式在索引期间更花时间(在LUCENE-888的测试中表明会多花7-33%的时间)。但是,注意这将极大的增加索引和搜索时的打开的文件数,所以如果你的mergeFactor设置过大的话,可能会耗尽可打开文件数。
  • 复用Document类和Field类对象的实例。
    Lucene 2.3为Field类增加了一个新方法setValue(...),这样你就可以修改一个Field类对象的值。这就允许你在许多添加的文档之间复用同一 个Field类的实例,这样可以减少大量的GC开销。最好是,创建单个Document类的实例,然后把多个Field类实例加之于上,然后保持这些 Field类的实例,针对每个加入的文档,修改他们的值复用他们。例如,你可能有一个idField,bodyField,nameField和 storeField等等。文档加入后,你就可以直接修改Field的值(idField.setValue(...),等等),然后把它们加入到你的对 象实例里。注意,你不能在一个Document内复用同一个Field,你应该在包含这个Field的Document加入到索引以后才修改Field的 值。参看Field了解细节。
  • 当你使用保存的字段或者词向量的时候,总是用相同的顺序把字段添加到你的文档。
    Lucene的合并有一种优化,依赖于对保存的字段和词向量进行的批量复制,但是只有在段间字段名->数字的映射保持一致的情况下才能实施。未来的Lucene可能会试图自动进行相同的映射(参见LUCENE-1737),但是到目前为止,获得相同映射的唯一途径就是总是用相同的顺序把字段加到索引内的每个文档中。
  • 在analyzer内复用同一个Token实例。
    analyzer通常都为序列中的每个term创建一个新的Token实例。你可以通过复用同一个Token实例的方法大幅节约GC的开销。
  • 在Token中使用char[] API取代String API来展现记号文本。
    在Lucene 2.3中,Token可以把他的文本用一个char数组的片段来表示,这可以节省GC的在new和回收String实例时造成的开销。通过复用同一个Token实例以及char[] API你可以避免每个词新建的所有对象。见Token了解详情。
  • 打开IndexWriter时,使用autoCommit=false选项。
    在Lucene 2.3中,包含了对保存字段和词向量的文档的显著优化,可以减少对非常大索引文件的合并操作。对一个长时间运行的IndexWriter使用 autoCommit=false选项,你就可以得到显著的性能提升。注意,然而这样的话,搜索器就只能在IndexWriter关闭的时候才能读取到索 引的变化;如果你非常需要在写入索引的同时可以搜索到最新更新的内容,那么你应该使用autoCommit=true选项,或者周期性的关闭和重新打开 writer。
  • 不去索引大量小文本字段,而是把文本聚合成一个单一的“内容”字段,并且仅索引(你还是可以索引其他的字段)。
  • 增大mergeFactor(合并因子),但是不要太大。
    mergeFactor越大段的合并则越晚,因为合并是索引中开销很大的一部分,所以这样做可以提高索引的速度。然而,这将降低搜索的速度,如果太大的话,你可能会耗尽文件描述符。太大的值也可能减缓索引速度,因为一次性合并越多的段,意味着越多的磁盘寻道。
  • 关闭所有你并未使用的特性。
    如果你存储了字段,但是查询期间并不使用的话,那么不要存储他们。词向量亦如是。如果你索引了太多的字段,关闭这些字段的norm可以提高性能。
  • 使用更快的analyzer。
    有时候,分析一个文档会花很长时间。例如,StandardAnalyzer非常耗时,尤其是在Lucene 2.2以下的版本的。如果你可以使用一个简单的analyzer,那么用它吧。
  • 加速document构建。
    从外部系统(数据库,文件系统,爬虫爬取的网站)获取一个document内容的常常是非常耗时的。
  • 除非你真的需要(更快的搜索),否则不要优化。
  • 多个线程使用一个IndexWriter。
    现代硬件高度并行(多核CPU,多通道内存架构,硬盘的内建指令队列,等等)。所以使用多线程添加文档多半会更快。即使是老的电脑,也经常在IO和CPU间存在并发。测试线程的数量选择性能最好的线程数量。
  • 索引分开不合并。
    如果你的索引内容非常的多,你可以把你的内容分为N块,在不同的机器索引每个块,然后使用writer.addIndexesNoOptimize把它们和并为最终索引。
  • 使用Java profiler。
    如果这些都失败了,profile你的程序找出时间耗费在哪里。我成功使用过一个非常简单的profiler叫做JMP。有很多java的profiler。往往你会很意外的发现,一些愚蠢的、意想不到的方法花费了那么多的时间。
  评论这张
 
阅读(3581)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017