亚马逊AWS官方博客
Amazon 通过回馈 Apache Lucene 得到了什么
可以说任何规模的搜索都非易事。而进行 Amazon 规模的搜索时,难度更是急剧上升:想想数十上百亿的产品,加上每天有成百上千万卖家在不断更改这些产品,还有上亿用户全天候搜索这一海量的数据。虽然 Amazon 多年来已经开发了自己的 C++ 搜索引擎来支持它的产品,但如今您在 Amazon 上搜索(或者您要求 Alexa 为您搜索)新书或洗碗机时,您会利用 Apache Lucene(“Lucene”)这一开源全文搜索引擎的强大力量。
为深入了解 Amazon 对 Lucene 的支持,我采访了 Mike McCandless,他是一位拥有 12 年经验的资深 Lucene 拥趸。McCandless 于 2017 年加入 Amazon,他说对于配置 Apache Lucene 来进行 Amazon 规模的运行,只要他能够继续向上游贡献更改,回馈开源的 Lucene 项目…
…这一“不可思议的挑战令人无法抗拒”。
为什么要使用 Apache Lucene?
在 Berlin Buzzwords 2019 大会上,McCandless(和 Amazon 搜索部门的同事 Mike Sokolov)介绍了在多年成功使用内部搜索引擎后,选择拥抱 Lucene 的原因。在后来与我讨论时,McCandless 强调此决定非同小可,因为我们拥有“极为庞大和高速的目录,延迟要求极高,峰值查询速率极大。” 优于这种严酷的要求,产品搜索团队最初不太确定 Lucene 能不能满足要求。
但评估一下总是值得的。为什么?
McCandless 说,首先 Lucene 已经吸引了极为庞大的粉丝社区,他们不断在进行该技术的迭代。其次,虽然我们可能担心 Lucene 能否满足我们的功能性和性能要求,但并非只有我们会将它严肃应用。Lucene “不是玩具”,McCandless 表示,“Twitter、Uber、LinkedIn 和 Tinder 等公司都在实际使用它。” Amazon 的许多其他团队也使用了 Lucene 多年,涉及多种应用程序,尽管以前还没有用于产品搜索。
最终,Lucene 的繁荣正是归功于这个成熟的用户社区,使它成为对 Amazon 产品搜索团队而言很有吸引力的一个选项。McCandless 指出,与 Amazon 的内部产品搜索服务相比,“Lucene 的功能更多,速度更快,有许多开发人员支持,拥有远远更多、经验丰富的搜索开发人员人才库,等等。”
所有这些尽管都无比真实,但并非完全是 Amazon 为上游 Lucene 做贡献的原因所在。
奉献更多,收获更多
McCandless 说,在将 Lucene 推向它的极限的同时,Amazon 开发人员发现了“毛边”、漏洞和其他问题。虽然 Apache 许可证(2.0 版) 允许开发人员修改代码,无需将更改贡献给上游社区,但 Amazon 选择主动回馈 Lucene 和其他项目。实际上,Amazon 开发人员一直在稳定加大参与开源项目的力度,以更好地服务客户,即使在搜索等可能创造竞争优势的战略性领域也是如此。
我们这样做有一些原因。
首先,正如 McCandless 所说,“社区是一个奇妙的资源:他们提出更改建议,让源代码变得更好。” 通过与 Lucene 社区协作,我们能够更好地帮助顾客更快找到他们需要的产品。
其次,我们希望与该社区合作,帮助促进主创新分支。确实,有时候会需要临时的分支,正如 McCandless 所说:“有时我们需要快速处理短期需求。但在我们完成更改后,我们会将它贡献给社区。在更改并入上游后,我们在上游版本的基础上重新调整分支,然后回到标准的 Lucene 发行版或快照。” 保持代码分支尽可能短暂,已经成为一个软件工程最佳实践,这部分要归功于众多开源项目开创的协作式开发流程。
秉承开源的贡献和收获精神,Amazon 已经向 Lucene 提出了多项重要的改进,包括:
- 并发更新和删除。如果将 Lucene 拥有简单的日志分析(例如将新文档附加到 Lucene 索引,但从不更新以前建立索引的文档),Lucene 的效果会非常好。而对于 Amazon 这类更新极多的工作负载,Lucene 在代码中有一个很小但十分重要的单线程段,用来将删除 ID 解析到文档中,这成为了此类使用案例的一个主要瓶颈。McCandless 承认, changes that McCandless 和团队贡献的更改正是需要“对 Lucene 索引代码进行的重大低级别更改”。他写道,“通过这次更改,
IndexWriter
仍会将删除和更新缓冲到数据包中,但与以前同时也为后来的单线程应用程序缓冲每个 数据包不同,现在IndexWriter
会立即使用当前索引线程,将数据包中的删除和更新解析到受影响的文档。这样基本做到了与您通过IndexWriter
发送的索引线程并发操作。” 结果如何? “并发硬件效率极大提升”(例如,更新整个文档时的索引处理速度提高 53%,更新文档值的速度提高了 7.4 倍 – 8.6 倍)。 - 建立自定义词语频率索引。Amazon 需要增加一项功能以将行为信号放入排名中(例如顾客在搜索某个东西后会做什么?),对于这项功能 Lucene 社区期盼已久。McCandless 的建议补丁? 创建“新令牌属性
TermDocFrequencyAttribute
并 调整索引链,以在该属性的值存在并且该字段的索引选项为DOCS_AND_FREQS
时将其作为词语频率使用。” 听起来很简单,对不对? 其实不然。“将行为信号纳入 Lucene 十分困难”,McCandless 指出。但由于“一旦我们增加了此功能,其他人可以加入进来,并在它的基础上进行构建”,这一工作可谓一箭双雕。 这种社区协作在有关如何优化实施 McCandless 的建议补丁的讨论中非常明显。 - 慵懒加载无限状态变送器。我们的第三个重要贡献来自 AWS 搜索服务团队的 Ankit Jain。Lucene 的无限状态变送器 (FST) 始终会在打开索引时加载到堆内存中,正如 Jain 所描述,它“会在词语词典极大时频繁导致 JVM [内存不足] 问题。” 他的解决方案是将 FST 移动到堆外,然后使用内存映射 IO 在空闲时间加载,从而确保仅词语索引的必要部分会加载到内存中。AWS 的这一贡献极大地提高了堆内存使用率,同时没有对常用索引的性能造成太大影响。
借助这些改进(更别提并发查询执行改进)和 Lucene 社区已经构建的丰富现有功能(例如 BM25F 评分、拆解、语言特定分词器),Amazon 搜索团队正在稳步实现在 2020 年将 Lucene 用于所有 Amazon 产品搜索的目标。我们开始 Lucene 产品搜索试验仅仅两年半就取得了如此瞩目的成绩,这要归功于支持 Lucene 开发的杰出社区。它让 Amazon 得以使用 Lucene 特有的功能(例如尺寸点和查询时间关联)来提升顾客购物体验。
Amazon 如何通过改进 Lucene 让我们的客户受益当然无比重要,但故事远远不止于此。
例如,Amazon 推送给 Lucene 的顾客词语频率贡献。对于 Amazon 而言,这可让我们将机器学习排名模型迁移到 Lucene。将行为信号添加到 Lucene 排名是一项非常“强大”的功能,McCandless 说,这一新功能让每个“Lucene 支持的”公司以及许多其他没有被列入 Apache 项目页面的人也可以借助此功能,更好地服务客户。Amazon 搜索团队可能已经在内部代码分支中建立了自定义词语频率功能,但除维护该分支的持续费用外,该团队还看到了与 Lucene 协作的更大价值,让该软件对所有人都变得更好。
上述并发更新/删除功能带来的效率改进也是如此。这当然对 Amazon 有帮助,但改进也有益于执行大量更新的任何 Lucene 用户。我们的目标是直接提升我们的客户体验,同时也向全世界开放这些强大的新增强。
对于 Amazon,不论是 Lucene、ROS(机器人操作系统)、Xen 或各种其他的开源项目,我们都知道,往往为客户提供良好长期体验的最佳方式,都需要投资开源软件,这是我们系统的一部分,尽管这些软件对客户不可见。我们对 Lucene 的贡献证明了我们积极参与开源软件,持续改革我们服务客户的方式的承诺。
后记:我们正在招聘
您是喜欢迎接艰巨挑战的 Lucene 专家吗? 请加入我们的行列。