作者:来自 Elastic Logan Pashby
深入了解 Logan Pashby 在 Cypris 的故事,讲述他如何为全球最大的创新数据库构建混合搜索。
Elasticsearch 拥有丰富的新功能,帮助你为自己的使用场景构建最佳搜索解决方案。深入阅读我们的示例笔记本,了解更多信息,开始免费云端试用,或立即在本地机器上尝试 Elastic。
“当我第一次在搜索中输入 ‘drone’,却看到没有设置同义词就出现了 ‘unmanned aerial vehicles’ 的结果时,我心想,‘哇,这东西真的懂我。’ 就在那一刻,我明白了——这真的像是魔法一样。” —— Logan Pashby,Cypris.ai 首席工程师
大规模相关性:Cypris 的搜索故事
Cypris 是一个平台,帮助研发和创新团队浏览超过 5 亿份专利和研究论文的海量数据集。他们的使命是让跟踪创新、寻找先前技术和了解推动新技术的组织变得更容易。
但他们遇到了一个问题。要获得相关结果,用户必须编写复杂的布尔查询语句 —— 这对专家用户来说没问题,但对许多其他用户却是个障碍。Cypris 需要一种更直观、更易用的搜索方式。
答案是由向量相似度驱动的语义搜索。然而,他们发现,在如此庞大的语料库上扩展语义搜索是一个棘手的工程难题。处理 5 亿个高维向量不仅仅是把它们塞进一个系统然后点击 “搜索” 那么简单。“当我们首次索引全部 5 亿个向量时,最糟糕的情况下查询时间长达 30 到 60 秒。”
这需要在模型复杂性、硬件资源和索引策略之间做出一系列深思熟虑的权衡。
Logan Pashby 是 Cypris 的首席工程师,专注于该平台的创新情报功能。他在深度学习、分布式系统和全栈开发等领域具有专业知识,致力于为研发和知识产权团队解决复杂的数据挑战,开发高效的搜索解决方案。
选择合适的模型
Cypris 最初尝试使用每个文档 750 维的向量嵌入进行向量搜索,但他们很快意识到,在 5 亿个文档中扩展如此大的嵌入是难以管理的。根据不使用量化的内存估算公式,所需的内存大约为 1500 GB,这让他们清楚地意识到需要调整策略。
“我们原本的假设和希望是,向量的维度越大,能够编码的信息就越多。更丰富的嵌入空间应该意味着更好的搜索相关性。”
他们曾考虑使用像 Elastic 的 ELSER 这样的稀疏向量,它通过将文档表示为加权的 token 列表来避免密集嵌入的固定维度限制。然而,当时 ELSER 只能使用 CPU 进行推理,对 Cypris 的数据集来说太慢。而密集向量则可以利用集群外的 GPU 加速,在生成嵌入时将吞吐量提高了 10 到 50 倍。

该团队最终选择了较低维度的密集向量,实现了平衡:这些向量足够紧凑,便于索引和搜索,同时又足够丰富,能保持结果的相关性。
在生产规模数据上实现可用
挑战 —— 磁盘空间
当 Cypris 的向量准备好要被索引时,他们面临下一个难题:如何在 Elasticsearch 中高效存储和搜索这些向量。
第一步是减少磁盘空间占用。“说到底,向量只是 float 数组……但当你有 5 亿个时,存储需求就会迅速增加。 ”默认情况下,Elasticsearch 会将向量存储多次:首先是在 _source 字段中(即原始 JSON 文档),然后是在 doc_values 中(用于优化检索的列式存储),最后是在 HNSW 图中。每个 750 维的 float32 向量大约占用 3KB,存储 5 亿个向量会迅速变得棘手,每一层存储都可能超过 1.5 TB。
Cypris 使用的一个实用优化是将向量从 Elasticsearch 的 source 文档中排除。这样可以减少开销,但事实证明磁盘空间并不是最大的问题,更大的挑战是内存管理。
你知道吗?
Elasticsearch 允许通过将向量从源文档中排除来优化磁盘空间。这可以显著减少存储成本,尤其是在处理大型数据集时。然而,需要注意的是,排除源中的向量会影响重建索引的性能。有关更多详细信息,请查看 Elasticsearch 关于源过滤的文档。
挑战 —— 内存爆炸
Elasticsearch 中的已知最近邻 (kNN) 搜索依赖于 HNSW 图,它们在完全加载到 RAM 中时表现最好。对于 5 亿个高维向量,系统的内存需求非常大。“尝试在查询时将所有这些向量加载到内存中并不是一件容易的事,” Logan 补充道。
Cypris 必须同时处理多个内存需求:向量及其 HNSW 图需要存储在 off-heap 内存中,以提供快速的搜索性能,而 JVM 堆内存必须保持可用,以支持其他操作。此外,他们还需要支持传统的关键词搜索,相关的 Elasticsearch 倒排索引也必须保持在内存中。
通过降维、量化和分段管理内存
Cypris 探索了多种方法来更好地管理内存和存储,以下是三种有效的方法:
-
低维向量:Cypris 团队选择使用较小的模型来减少向量大小,从而降低资源需求。
-
BBQ(Better Binary Quantization):Cypris 曾考虑使用 int8 量化,但当 Elastic 发布 BBQ 时,Cypris 快速采纳了它。“我们进行了测试,它对相关性的影响不大,而且成本显著降低。所以我们立即实施了它,” Logan 说。BBQ 立即将他们的向量索引大小减少了大约 20%!
你知道吗?
Elasticsearch 的二进制量化向量(BBQ)可以将向量索引的大小减少约 20%,且对搜索相关性的影响最小。BBQ 通过缩小索引大小减少磁盘使用,同时由于较小的向量在搜索期间占用更少的 RAM,它还减少了内存使用。这对于使用 HNSW 图扩展 KNN 搜索特别有帮助,因为在内存中保持所有内容对性能至关重要。探索 BBQ 如何优化你的搜索基础设施,请参阅 Elasticsearch 关于向量搜索的文档。
-
分段和分片调优:Cypris 还优化了 Elasticsearch 如何管理分段和分片。HNSW 图是在每个分段中构建的,因此搜索密集向量意味着在一个分片中的所有分段上查询。正如 Logan 解释的:“HNSW 图在每个分段内是独立的,每个密集向量字段搜索都涉及在每个分段中查找最近邻,这使得总成本依赖于分段的数量。”
较少的分段通常意味着更快的搜索,但过度合并它们可能会减慢索引速度。由于 Cypris 每天都要处理新文档,他们定期强制合并分段,以将它们的大小保持在默认的 5GB 阈值以下,保留自动合并和墓碑垃圾回收。为了平衡搜索速度与索引吞吐量,强制合并发生在低流量期间,且分片大小保持在健康范围内(低于 50GB),以优化性能而不牺牲数据摄取速度。
更多向量,更快搜索,用户更满意
通过这些优化,Cypris 将查询时间从 30-60 秒缩短到 5-10 秒。他们还发现,60-70% 的用户查询从之前的布尔搜索体验转向了新的语义搜索界面。
但团队并没有就此止步!他们的目标是实现毫秒级查询,以支持快速的迭代搜索,并让大多数用户转向语义搜索。
Cypris 团队学到了什么?……接下来是什么?
500 百万向量不能自动扩展
处理 500 百万向量不仅仅是存储问题或搜索问题 —— 它是两者的问题。Cypris 必须在每一步中平衡搜索相关性、硬件资源和索引性能。
你知道吗
Elasticsearch 的 _search API 包含一个 profile 功能,可以分析搜索查询的执行时间。这有助于识别瓶颈并优化查询性能。启用配置文件功能后,你可以了解查询中不同组件是如何被处理的。了解更多关于在 Elasticsearch 搜索分析文档中的 profile 功能。
在搜索中,总是有权衡
BBQ 是一个重大的胜利,但它并没有消除重新考虑分片、内存分配和索引策略的需求。减少分片数量提高了搜索速度,但使得索引变得更慢。从源文档中排除向量减少了磁盘空间,但也使得重新索引变得更加复杂,因为 Elasticsearch 不保留重新创建索引时所需的原始向量数据。每个优化都有成本,必须仔细权衡。
优先考虑用户,而不是模型
Cypris 并没有追求最大模型或最高维度的向量。他们专注于对用户有意义的东西,并从那里反推。“弄清楚你的数据的相关性意味着什么,” Logan 建议,“然后从那里反推。”
Cypris 现在正在扩展到其他数据集,这可能使他们需要在 Elastic 中索引的文档数量翻倍。他们需要快速行动以保持竞争力,“我们是一个小团队,”Logan 说,“所以我们做的每件事都必须能够扩展 —— 而且必须有效。”
了解更多,请访问 cypris.ai