如何使用向量数据库向量空间对话来增强您的语义搜索能力
Demetrios Brinkmann
·2024年1月9日

如何与 Nicolas Mauti 一起使用向量数据库来增强您的语义搜索能力
“我们发现在 Qdrant 中性能和精度之间的权衡对我们来说比在 Elasticsearch 中发现的更好。”
– Nicolas Mauti
想要在自由职业者搜索中兼顾精度和性能?Malt 转向 Qdrant 数据库是一项妙举,提供了地理空间过滤和无缝扩展。Nicolas Mauti 和 Malt 团队是如何识别出需要为他们的自由职业者匹配应用过渡到检索器-排序器架构的呢?
Nicolas Mauti,INSA Lyon 工程学院计算机科学毕业生,从软件开发转向数据领域。他于 2021 年加入 Malt 担任数据科学家,专注于自由职业者与公司市场中的推荐系统和自然语言处理模型。随后,他发展成为一名 MLOps 工程师,Nicolas 熟练地结合数据科学、开发和运维知识,以增强 Malt 的模型开发工具和流程。此外,自 2020 年以来,他一直在一所法国工程学院担任兼职教师。值得注意的是,2023 年,Nicolas 在 Malt 成功大规模部署了 Qdrant,为新的匹配系统的实施做出了贡献。
在 Spotify、Apple Podcast、Podcast addicts、Castbox 上收听本期节目。您也可以在 YouTube 上观看本期节目。
主要收获
深入了解 Malt 的 MLOps 工程师 Nicolas Mauti 如何提升语义搜索的复杂性。探索 Nicolas 和他的团队如何在 Malt 彻底改变自由职业者与项目连接的方式。
在本期节目中,Nicolas 深入探讨了通过实施带有多语言基于 Transformer 模型的检索器-排序器架构来增强 Malt 的语义搜索,通过过渡到 Qdrant 将延迟从 10 秒减少到 1 秒,从而改善自由职业者与项目的匹配,并提升平台的整体性能和扩展能力。
从本集学习的 5 个关键点
- 性能提升策略:了解 Malt 因业务扩展到超过五十万自由职业者而面临的延迟增加的技术挑战,以及他们采取的解决方案。
- 高级匹配架构:了解 Malt 采用的检索器-排序器模型,该模型结合了语义搜索和 KNN 搜索,以提高项目与自由职业者配对的效率。
- 前沿模型训练:揭示多语言基于 Transformer 的编码器的部署,该编码器有效地创建高保真嵌入以简化匹配过程。
- 数据库选择过程:Mauti 讨论了影响 Malt 数据库系统选择的因素,这些因素在高性能和准确过滤能力之间实现了平衡。
- 运营改进:了解 Malt 在部署后取得的重大进展,包括应用程序延迟的显著降低及其对可扩展性和匹配质量的积极影响。
趣闻:Malt 采用了一种多语言基于 Transformer 的编码器模型来生成 384 维嵌入,这提高了他们的语义搜索能力。
笔记
00:00 匹配应用遇到严重的性能问题。
04:56 筛选自由职业者并采用检索器-排序器架构。
09:20 用于适应语义空间的多语言编码器模型。
10:52 审查、再训练、分类和组织自由职业者的回应。
16:30 地理空间过滤数据库的困境
17:37 基准测试搜索算法的性能和精度。
21:11 部署在 Kubernetes 中。存储在 Git 存储库中,与 Argo CD 同步。
27:08 快速改善延迟,验证架构,调整步骤。
28:46 邀请讨论使用特定方法的工作。
Nicolas 的更多引述
“因此 GitHub 的方法是基本思想,即您的 git 存储库是关于您在 Kubernetes 集群中必须拥有的内容的真实来源。”
– Nicolas Mauti
“所以我们可以看到我们的空间似乎组织得很好,技术自由职业者彼此靠近,而图形设计师,例如,则远离技术家族。”
– Nicolas Mauti
“还有一件事引起我们兴趣的是它是多语言的。由于 Malt 是一家欧洲公司,我们必须拥有一个多语言模型。”
– Nicolas Mauti
文字记录
Demetrios:我们上线了。我们真人上线了。Nicholas,很高兴你能来这里,老兄。欢迎所有向量空间探索者。我们又回来进行另一场向量空间对话了。今天我们将讨论如何使用我的朋友 Nicholas(Malt 的 ML 运维工程师)来增强您的语义搜索能力,以防您不知道 Malt 在做什么。他们正在配对,他们正在建立一个市场。他们正在连接自由职业者和公司。
Demetrios:Nicholas,你在推荐系统方面做了很多工作,对吗?
Nicolas Mauti:是的,没错。
Demetrios:我喜欢那样。嗯,正如我所说,我处于一个有趣的位置,因为我正在努力吸收所有的维生素 D,同时听你的演讲。所有在场的人,请参与进来。告诉我们你从哪里打电话或观看。另外,请随时在聊天中提出问题,如果需要,我将介入并打断 Nicholas。但我知道你有一个小小的演示要给我们看,老兄,你想进入它。
Nicolas Mauti:谢谢你的,谢谢你的介绍,大家好。当然,也谢谢你们邀请我参加这次演讲。那么,我们开始吧。动手吧。
Demetrios:我喜欢。超能力。
Nicolas Mauti:是的,演示结束后我们都会拥有超能力。所以,大家好。我想介绍已经由 Dimitrios 完美完成了。我是 Nicola,是的,我作为一名 Malt 的 MLOps 工程师工作。同时我也是法国一所工程学校的兼职教师,教授一些 MLOps 课程。那么,让我们深入今天的主题。事实上,正如 Dimitrio 所说,Malt 是一个市场,所以我们的目标是一方面匹配自由职业者。这些自由职业者有很多属性,例如描述、一些技能和一些很棒的技能。
Nicolas Mauti:他们也有一些偏好,还有一些并非语义的属性。所以这将是我们今天话题的关键点。另一方面,我们有所谓的项目,由公司提交。这些项目也有很多属性,例如描述、一些技能以及需要找到的属性,还有一些偏好。所以我们的最终目标是在这两个实体之间进行匹配。为此,我们已经有一个匹配应用在生产中。事实上,我们这个应用有一个主要问题,就是它的性能,因为应用变得非常慢。P50 延迟约为 10 秒。
Nicolas Mauti:你需要记住的是,如果你的延迟过高,你将无法执行某些场景。有时你想要一些同步场景,你填写完项目后,就想直接看到与该项目匹配的自由职业者。如果这花费太多时间,你就无法实现,你就不得不采用一些异步场景,比如通过电子邮件或其他方式。这不是一个很好的用户体验。此外,这个平台呈指数级增长,加剧了这个问题。当然,我们正在发展。所以给你一些数字,我两年前来的时候,我们的自由职业者少了两次。
Nicolas Mauti:今天,今天我们的数据库中大约有 60 万名自由职业者。所以它正在增长。随着这种增长,我们遇到了一些问题。关于这个匹配应用程序,我们需要记住一件事。它不仅仅是语义应用程序,它有两件事是非语义的。我们有所谓的硬性过滤器。硬性过滤器是 Malt 项目团队定义的硬性规则。这些规则是硬性的,我们必须遵守它们。
Nicolas Mauti:例如,问题是 Malt 的硬性规则,我们采用本地方法,因此我们希望提供与项目相邻的自由职业者。为此,我们必须过滤自由职业者,并为此设置硬性过滤器,以确保我们遵守这些规则。另一方面,正如您所说,Demetrios,我们在这里谈论的是 Rexis 系统。因此,在 Rexis 系统中,您还必须考虑其他一些参数,例如自由职业者的偏好,以及自由职业者在平台上的活动,例如。因此,在我们的系统中,我们必须记住这一点并使其正常工作。因此,如果我们大致了解我们的系统如何工作,我们一开始有一个 API,带有一些过滤器,然后是主要语义的 ML 模型,然后是一些带有其他参数的重新评分函数。因此我们决定重做此架构并采用检索器-排序器架构。因此,在此架构中,您将拥有自由职业者池。
Nicolas Mauti:所以这里是您的所有数据库,也就是您的 60 万自由职业者。然后您将有一个称为检索的第一步,我们将构建您的自由职业者的一个子集。然后您可以应用您的错误杀伤算法。这基本上是我们的当前应用程序。所以第一步将是语义上的,它必须很快,因为您必须快速选择您最感兴趣的自由职业者,而且它是为召回率而构建的,因为在这一步您要确保所有相关的自由职业者都被选中,并且您不想在这一步排除一些相关的自由职业者,因为排名将无法找回这些自由职业者。另一方面,排名可以包含更多特征,不仅仅是语义,它的时间开销更少。如果您的检索部分总是给您固定大小的自由职业者,您的排名就不必扩展,因为您总是会有相同数量的自由职业者作为输入。而这一部分是为精度而构建的。
Nicolas Mauti:在这一点上,你不希望保留不相关的自由职业者,你必须能够对他们进行排名,而且你必须在这方面达到最先进的水平。所以让我们关注第一部分。这就是我们今天感兴趣的。因此,对于第一部分,事实上,我们必须构建这个语义空间,在这个空间中,技能或工作相关的自由职业者也彼此靠近。因此,我们将构建这个语义空间。然后,当我们收到一个项目时,我们只需要将这个项目投影到我们的空间中。之后,你只需要进行搜索和 KNN 搜索,即最近邻搜索。实际上,我们不做 KNN 搜索,因为它太昂贵了,而是做近似最近邻搜索。
Nicolas Mauti:记住这一点,它将在我们接下来的幻灯片中很有趣。因此,要获得这个语义空间并进行这种搜索,我们需要两样东西。第一个是模型,因为我们需要一个模型来计算一些向量,并将我们的机会、项目和自由职业者投影到这个空间中。另一方面,您需要一个工具来操作这个语义步骤页面。因此,既要存储向量,又要执行搜索。对于第一部分,对于模型,我将给您一些关于我们如何构建它的快速信息。因此,对于这一部分,更多的是数据科学家的部分。因此,数据科学家从一个 E5 模型开始。
Nicolas Mauti:因此,E5 模型将为您提供关于语言的通用知识。还有一件事让我们感兴趣的是它是多语言的。由于 Malt 是一家欧洲公司,我们必须拥有一个多语言模型。在此基础上,我们构建了我们自己的基于 Transformer 架构的编码器模型。因此,这个模型将负责适应 Malchus 的用例,并将这个非常通用的语义空间转换为用于技能和工作的语义空间。这个模型还能够考虑自由职业者个人资料的结构,因为您有描述和工作、一些技能、一些经验。因此,这个模型能够将这些考虑在内。关于训练,我们使用平台上的历史交互来训练它。
Nicolas Mauti:因此,当一位自由职业者收到一个项目时,他可以选择接受或不接受。我们利用这一点来训练这个模型。最终,我们得到了具有 384 维的嵌入。
Demetrios:我有一个问题,抱歉打断你。你是否进行任何类型的审查或反馈并将其添加到模型中?
Nicolas Mauti:是的。事实上,我们仍然会收到自由职业者的回复。所以我们也会审查它们,有时是人工审查,因为有时回复不是很好,或者我们没有得到我们想要的,或者诸如此类的事情,所以我们可以审查它们。我们还会定期重新训练模型,这样我们就可以纳入自由职业者的新反馈。现在我们有了模型,如果我们想看看它是什么样子。所以在这里我画了一些池塘,并根据自由职业者的类别给它们上色。所以在平台上,自由职业者可以有类别,例如技术或图形或很快的设计师或这类类别。所以我们可以看到我们的空间似乎组织得很好,技术自由职业者彼此靠近,而图形设计师例如,则远离技术家族。
Nicolas Mauti:所以它似乎组织得很好。现在我们有一个好的模型。好的,现在我们有了模型,我们必须找到一种方法来操作它,以便存储这些向量并执行我们的搜索。为此,VectorDB 似乎是一个不错的选择。但是如果你关注新闻,你会发现 VectorDB 非常流行,市场上有大量的参与者。所以找到你的真爱可能会很困难。所以我将尝试给你我们拥有的标准以及我们最终选择 Qdrant 的原因。所以我们的第一个标准是性能。
Nicolas Mauti:我想我已经谈过这些了,但是是的,我们需要性能。第二个是关于内在质量。正如我之前所说,我们不能每次都进行 KnN 搜索,暴力搜索。所以我们必须找到一种近似但足够接近且足够好的方法。否则,我们将无法利用我们模型的性能。最后一个,我之前没有太多谈到的是过滤。过滤对我们来说是一个大问题,因为我们有很多过滤器,正如我之前所说,是硬性过滤器。所以如果我们考虑我的架构,我们可以说,好的,所以过滤不是问题。
Nicolas Mauti:您可以简单地采用三步流程:过滤、语义搜索,然后排名;或者语义搜索、过滤,然后排名。但在这两种情况下,如果这样做,您都会遇到一些麻烦。第一个是,如果您想应用预过滤。所以过滤、语义搜索、排名。如果您这样做,事实上,您将不得不,所以我们将拥有这种架构。如果您这样做,事实上,您将不得不在查询向量数据库并执行搜索之前,标记每个自由职业者是否可以被选中。因此,您将基本上在自由职业者池中创建一个二进制掩码。随着您拥有的自由职业者数量的增长,您的二进制掩码也会增长。
Nicolas Mauti:所以它不是很可扩展。至于性能,它会随着自由职业者基数的增长而下降。您还会遇到另一个问题。许多向量数据库(Qdrant 是其中之一)使用哈希 NSW 算法进行内部搜索。这种算法基于图。所以如果您这样做,您将停用图中的一些节点,您的图将变得不连通,您将无法在图中导航。所以您的匹配质量会下降。因此,应用预过滤绝对不是一个好主意。
Nicolas Mauti:所以,不,如果我们进行后过滤,我想这个问题更清楚。您将拥有这种架构。因此,事实上,如果您这样做,您将不得不为您的向量数据库检索大量的自由职业者。如果您应用一些非常激进的过滤并排除大量的自由职业者,您将不得不向您的向量数据库请求大量的自由职业者,因此您的性能将受到影响。所以过滤是一个问题。所以我们不能进行预过滤或后过滤。所以我们必须找到一个能够同时进行过滤和匹配以及语义匹配和搜索的数据库。Qdrant 是其中之一,市场上还有其他的。
Nicolas Mauti:但在我们的案例中,有一个过滤器给我们带来了很多麻烦。这个过滤器就是地理空间过滤,很少有数据库支持这种过滤,我认为 Qdrant 是其中一个支持它的。但是没有很多数据库支持它。我们绝对需要它,因为我们有本地方法,我们希望确保我们推荐的自由职业者靠近项目。所以现在我说完了所有这些,我们有三个候选者进行了测试和基准测试。我们有 elasticsearch PG vector,它是 PostgreSQL 的一个扩展,还有 Qdrant。在这张幻灯片上,你可以看到 Pycon 等,Pycon 因为缺乏地理空间过滤而被排除。所以我们根据 QPS(每秒查询次数)对它们进行了基准测试。
Nicolas Mauti:所以每秒查询次数。这个是为了性能,你可以看到 Qdrant 远远领先于其他产品,我们还根据精度对其进行了基准测试,我们如何计算精度,对于精度我们使用了一个名为 textmax 的语料库,Textmax 语料库提供了 100 万个向量和 1000 个查询。对于每个查询,您都有最接近向量的真实值。他们为此使用了暴力 KNN。所以我们将这些向量存储在我们的数据库中,我们运行查询,并检查我们找到了多少在真实值中的向量。所以他们为您提供了一个内部算法精度的度量。对于这个指标,您可以看到 Elasticsearch 比 Qdrant 略好,但事实上我们能够稍微调整 AsHNSW 算法和索引的参数。最终我们找到了更好的权衡,我们发现在 Qdrant 中性能和精度之间的权衡对我们来说比在 Elasticsearch 中发现的更好。
Nicolas Mauti:所以最终我们决定选择 Qdrant。现在我们有了模型,也有了操作它们的工具,可以操作我们的模型。所以本次演示的最后一部分将是关于部署的。我将简要谈谈它,因为我认为它很有趣,而且它也是我作为开发工程师工作的一部分。所以关于部署,我们首先决定在集群配置中部署 Qdrant。我们决定从三个节点开始,然后我们决定获取我们的集合。集合是所有向量存储在 Qdrant 中的地方,它就像 SQL 中的表或 Elasticsearch 中的索引。所以我们决定将我们的集合拆分到三个节点之间。
Nicolas Mauti:这就是我们所说的分片。所以你在每个节点上都有一个集合的分片,然后对于每个分片,你有一个副本。副本基本上是分片的一个副本,它存在于与主分片不同的节点上。这样你就在另一个节点上有一个副本。因此,如果我们在正常情况下操作,你的查询将分布在你的三个节点上,你将相应地得到响应。但有趣的是,如果我们丢失一个节点,例如这个节点,例如,因为我们正在执行滚动升级,或者因为 kubernetes 总是杀死 Pod,我们仍然能够操作,因为我们有副本可以获取我们的数据。所以这种配置非常健壮,我们对此非常满意。至于部署。
Nicolas Mauti:正如我所说,我们将其部署在 Kubernetes 中。我们使用了 Qdrant M chart,这是 Qdrant 提供的官方 M chart。事实上,我们将其作为子图表,因为我们需要集群中的一些额外组件和一些自定义配置。所以我没有谈论这些,但 M chart 只是一堆 Yaml 文件,它们将描述您在集群中操作数据库所需的 Kubernetes 对象,在您的情况下,它是一系列文件和模板来完成这项工作。当您在 Malt 拥有这些时,我们正在使用我们所说的 GitHub 方法。因此,GitHub 方法的基本思想是您的 git 存储库是关于您在 Kubernetes 集群中必须拥有的内容的真实来源。因此,我们将这些文件和这些 M chart 存储在 git 中,然后我们有一个名为 Argo CD 的工具,它会在某个时间拉取我们的 git 存储库,并检查我们 git 中的内容与我们集群中的内容以及我们集群中正在运行的内容之间的差异。然后它会将我们 git 中的内容直接同步到我们的集群中,无论是自动还是手动。
Nicolas Mauti:所以这是一个很好的协作方法,可以确保我们 Git 中的内容与集群中的内容一致。并且只需查看 Git 存储库即可了解集群中的内容。我想这就是全部了,我想还有一张幻灯片会让你感兴趣。这是关于项目成果的,因为我们在 Malt 做了这些。我们构建了这种架构,第一阶段使用 Qdrant 进行语义匹配并应用我们所有的过滤器。在第二阶段,我们保留了我们所有的排序系统。所以如果我们看一下我们应用程序的延迟,也就是我们应用程序的 P50 延迟,它是一个包含两个步骤的完整应用程序,包含过滤器、语义匹配和排名。正如你所看到的,我们在 10 月中旬开始进行辩论测试。
Nicolas Mauti:在此之前,延迟大约是 10 秒,正如我在演讲开始时所说。所以我们已经看到了应用程序的巨大下降,我们决定在 12 月全面上线,我们又看到了一个大的下降。所以我们之前大约是 10 秒,现在大约是 1 秒半。所以我们将延迟降低了五倍以上。这对我们来说是一个非常好的消息,因为首先它更具可扩展性,因为检索器非常可扩展,而且随着 Qdrant 的集群部署,如果需要,我们可以添加更多节点,并且我们将能够扩展这个阶段。在那之后,进入匹配部分的自由职业者数量是固定的。所以匹配部分现在不必扩展。
Nicolas Mauti:另一个好消息是,现在我们能够扩展,并且第一部分之后我们的尺寸是固定的,我们能够构建更复杂和更好的匹配模型,我们将能够提高匹配的质量,因为现在我们能够扩展并处理更多的自由职业者。
Demetrios:这太不可思议了。
Nicolas Mauti:是的,当然。这对我来说是个非常好的消息。就这样。也许你们有很多问题,也许我们可以讨论一下。
Demetrios:好的,首先,我想向所有正在观看或阅读此内容的自由职业者致敬,我认为现在是加入 Malt 的绝佳时机。看起来它每天都在变得更好。我知道会有问题陆续出现,但我们已经收到了 Luis 的一个问题。Luis 怎么样?他问道,在考虑 Qdrant 之前,你们使用的是什么 Ann 库或服务?
Nicolas Mauti:所以之前我们没有任何库或服务,或者我们没有像现在这样进行任何 Ann 搜索或语义搜索。我们只有一个模型,当我们同时将自由职业者和项目传入模型时,最终会得到相关性评分。所以这就是为什么它如此缓慢,因为你必须构建每一对并将其发送给你的模型。所以现在我们不必这样做,所以它好得多。
Demetrios:是的,这很合理。我有一个问题,你花了多长时间,我想你说你从十月份开始 A/B 测试,然后在十二月份推出。你最后一张幻灯片是什么?
Nicolas Mauti:是的,就是那个。
Demetrios:为什么犹豫不决?为什么从十月到十二月才降下来?你当时不确定什么?因为感觉你看到了一个巨大的下降,那为什么等到十二月呢?
Nicolas Mauti:是的,关于延迟和延迟的下降,结果很快就非常清楚了。我想大概一周后,我们就确信延迟更好了。首先,我们的想法是验证架构,但第二个原因是确保我们没有降低匹配的质量,因为我们有两个步骤的过程。风险是两个模型彼此不一致。因此,如果您的第一步和第二步的交集不够好,您最终将只得到一些空结果,因为您的第一部分将选择一部分自由职业者,而第二步将选择另一部分,所以您的交集是空的。因此,我们的目标是评估这两个步骤是否对齐,从而我们没有降低匹配的质量。关于我们拥有的项目数量,我们不得不等待大约两个月。
Demetrios:完全明白了。好的,老兄,我真的很感谢你。你能回到那张幻灯片,上面显示了如果人们想联系你,了解更多信息,他们如何与你联系吗?我鼓励大家这样做。非常感谢,Nicholas。太棒了,老兄。
Nicolas Mauti:谢谢。
Demetrios:好的,各位。顺便说一句,如果您想加入我们,谈论您正在做什么,以及您如何使用 Qdrant,或者您在语义空间或语义搜索或向量空间中正在做什么,所有这些有趣的事情,请联系我们。我们很乐意邀请您加入。Nicola,最后一个问题。有人提到了一个问题。您使用哪种索引方法?它适合使用 OpenAI 嵌入吗?
Nicolas Mauti:所以就我们而言,我们有自己的模型来构建嵌入。
Demetrios:是的,我记得你一开始就说过。好的,太棒了。谢谢你,伙计,我们下周再见,再进行一次向量空间对话。感谢大家的加入,保重。谢谢。