Apache Lucene 2.9 的改进

  • Charles Humble
  • 赵劼

2009 年 10 月 7 日

话题:Java开源DevOps语言 & 开发架构

Lucene 2.9 的大部分重心放在了性能优化方面,这体现在从低端的内部基础结构改进到索引管理方式等多个方面。Lucene 的索引数据库由一系列分离的“片断”组成,每个片段存放在独立的文件中。当你向索引中添加文档时,便会不断创建一些可以合并的新片断。Lucene 会在 FieldCache 中缓存字段信息,不过在 Lucene 2.4 以及之前的版本中,加载字段缓存的开销相对较高,尤其在 2.4 版本中还会不断重新加载整个字段缓存。在发布 2.9 版本的准备过程中,Lucene 团队意识到,在进行合并或删除的时候片断的改变频率通常比较高,不过较早的片断则更趋向于保持不变。因此,修改后的字段缓存只会加载更新过的片断。

Lucene 跨片断加载 FieldCache 的效率也不够好。因此,2.9 版本会为每个片段分别管理 FieldCache,以此避开跨片断加载 FieldCache 的需求。这个改变的效果非常明显,Lucid Imagination 的 Mark Miller运行了一个简单的性能测试,表明在 5,000,000 个不同字符串下的情况下,Lucene 2.9 相对于 2.4 版本会获得 15 倍左右的性能提高:

Lucene 2.4: 150.726s

Lucene 2.9: 9.695s

另一个显著的性能提高在于重开(re-opening)搜索的时候。Lucene 2.9 引入了新的IndexWriter.getReader()方法,它可用于搜索目前完整的索引,包括当前 IndexWriter 会话中还没有提交的改变,这带来了接近于实时搜索的能力。此外,你还可以调用IndexWriter.setMergedSegmentWarmer()方法进行“预热”,这样那些片断便可以立即投入使用了。

另一个重大变化则是数字的处理方式,尤其是在范围查询(如“给我找出价格在 0.5 到 9.99 英镑之间的 CD”)的场景下。在 2.9 版之前,Lucene 的查询完全基于文本,因此对于数字的处理则变成了基于字符串的精确编码。这种做法经常会生成大量独立的关键字,Lucene 需要通过遍历的方式来构建整个结果集。在此之前,许多开发人员使用了自定义的编码规则来应对这种情况,不过 Lucene 2.9 已经自带对数字的处理方式。Field 和 Query 类会采取合适的精度进行索引和搜索,这样大大降低了需要搜索的关键字数量,使查询的响应能力得以显著提高。

2.9 版本还引入了新的查询类型和适用性更广的多关键字查询(通配、前缀等等)方式,以及新的针对波斯语,阿拉伯语及中文的分析器。此外,这次更新还包括更好 Unicode 支持,一个新的查询分析框架,以及对地理位置的查询,它允许根据距离信息对文档进行过滤和排序(如“找出我家 5 英里范围内的所有干洗店”)。你可以在这里找到完整的改进列表。

一般来说,Lucene 会在主要版本之间保持完整的兼容性,但是 CHANGES.txt 的“向后兼容策略”一节中列举了 Lucene 2.9 在许多地方对兼容性的破坏。对于 2.9 版本的升级操作很可能需要一次重新编译,合适完整的回归测试以及其它在这方面的努力。基于 2.9 版本的重新编译也会提示出所有即将被废弃的方法,这样开发人员便可以升级他们的应用程序,并为 3.0 版本作好准备。这是个明智的做法,因为 Lucene 3.0 会放弃对 Java 1.4 的支持,并且删除所有 2.9 版本中被标记为“deprecated”的功能。

查看英文原文:Apache Lucene 2.9 Released
Java开源DevOps语言 & 开发架构