AI 应用开发:pgvector 在文本搜索中的革命(上篇)
文章略长,分成两部分。
PostgreSQL 已经成为顶级的关系型数据库有一段时间了。现在,在人工智能时代,我们还需要存储向量数据以实现快速且相似的搜索。这就是 pgvector 的用武之地——它就像 PostgreSQL 的一个插件,帮助它很好地处理向量数据。
什么是向量数据?
想象你有一张地图,但上面不是城市和街道,而是你最喜欢的东西:电影、音乐和有趣的猫视频。每样东西都像地图上的一个点,如果这些点很接近,就意味着它们很相似。例如,一部喜剧电影的点可能靠近另一部喜剧,但与科幻电影的点就不那么接近。在数字世界中,向量就像地图上的点,代表信息,如文本或图像。通过比较这些点的接近程度,我们可以判断事物的相似性,即使它们使用不同的词汇或看起来有点不同。这就像一种计算机能理解的超越文字或像素含义的秘密语言——有点像魔法,但用的是数学!我们将向量数据表示为浮点数列表。
例如:[0.5, 1.2, -0.3, 4.7] 代表一个四维向量。
pgvector - 文本搜索的革命
想象一下普通的文本搜索就像一个侦探仔细地逐字检查文件,以找到匹配的内容。现在,pgvector 更像是一个 AI 代理。它将文本、图像或声音存储为高维向量,就像捕捉数据核心含义的数字指纹。如上所述,如果两个向量在这个空间中很接近,就意味着它们在意义上非常相似。这就是余弦距离的用武之地。这种余弦度量查看两个向量之间的角度,如果角度小,就意味着它们非常相似。
本地安装 pgvector
为了便于使用,我们将 pgvector 打包成了一个 docker 镜像,里面还包含了其他一些常用的功能,比如时序数据库 timescaledb、空间数据库插件 postgis 等。
下载方法:
使用方法:
创建 pgvector:
我们也提供了在线直接使用的方式,可以在文末找到链接。
pgvector 解决了什么问题?
pgvector 旨在解决 PostgreSQL 在搜索和数据表示方面的几个关键问题:
有限的文本和数据表示:传统的 PostgreSQL 以简单的格式存储数据,如文本、数字和日期。这种缺乏灵活表示的方式使得捕捉复杂数据点(如文本文档、图像或科学数据)之间的真实含义和关系变得困难。pgvector 引入了多维向量作为一种数据类型,允许基于其固有质量和关系对数据进行更丰富的表示。此外,pgvector 的基于向量的方法,结合 HNSW 和 IVFFlat 等索引技术,使得在大型数据集上进行更快速、更高效的搜索成为可能,为实时应用程序和大数据环境提供可扩展性。
低效的相似性搜索:传统的 PostgreSQL 文本搜索依赖于关键字匹配或模式识别,这在寻找相似文档或内容时可能会很慢,也不能用于执行基于数据含义的搜索。pgvector 基于余弦距离等高级距离度量实现高效的相似性搜索,允许您找到即使不共享相同单词或模式也具有相似含义的项目。
缺乏与机器学习的集成:pgvector 通过使 PostgreSQL 与机器学习模型生成的向量嵌入无缝集成,弥合了 PostgreSQL 和机器学习之间的差距。这使您能够直接在 PostgreSQL 数据库中利用机器学习的强大功能,用于文档检索、图像搜索和推荐系统等任务。
pgvector 支持两种主要类型的搜索——精确近邻搜索(ENN)和近似近邻搜索(ANN)。ENN 和 ANN 都专注于在高维空间中寻找相似的向量,但它们的方法不同,也有不同的优缺点
精确近邻搜索(ENN)定义:
在数据集中找到与查询向量完全相同的向量。
算法:采用暴力方法,将查询向量与数据库中的每个向量进行比较。
准确性:保证找到真正的最近邻,确保最高可能的精度。
性能:需要将查询向量与所有可用向量进行比较,导致可能的慢速计算和高资源消耗,特别是对于大型数据集。
常见用例:当绝对精度至关重要时,例如在关键的财务计算或科学分析中。
近似近邻搜索(ANN):
在一定容差内找到与查询向量大致相似的向量。
利用索引技术识别候选向量,而无需将它们全部比较,显著减少搜索空间。
提供近似答案,可能错过真正的最近邻,但通常返回接近的替代品。
与 ENN 相比,提供更快的搜索时间和更低的资源消耗,适合大型数据集和实时应用程序。
当实时响应和可扩展性优先于绝对精度时,例如在推荐系统、图像/视频检索和自然语言处理应用程序中。
选择 ENN 还是 ANN 取决于您的具体需求:
准确性:如果您需要以最高精度找到绝对最接近的匹配,ENN 是您的选择。
性能:对于实时应用程序和大型数据集,ANN 提供了更快的速度和资源效率。
数据大小:数据集越大,人工神经网络的性能优势就越显著。
对不准确的容忍度:想想在你的应用程序中有一个势均力敌的匹配是多么好。
额外因素:
距离度量:ENN 和 ANN 都可以使用各种距离度量,如 L2、内积和余弦距离。
索引技术:不同的 ANN 算法,如 HNSW 和 IVF,提供不同的性能和准确性权衡。
L2 距离、内积和余弦距离的简单示例解释:
想象两个苹果在一个水果篮子里:
L2 距离:这告诉你篮子里苹果之间的距离,就像测量它们之间的直线距离。距离越大,它们越不相似。当你需要知道事物之间的确切差异时,比如地图上的距离或价格差异,就会使用它。
内积:这就像比较苹果的味道和质地。高内积意味着它们都是甜的和脆的,而低内积意味着它们不同(也许一个是酸的,另一个是软的)。当你想要比较事物在特定品质上的相似性时,比如比较具有相似主题的文档或具有相似节奏的音乐时,就会使用它。
余弦距离:假设每个苹果顶部都有一个小箭头,指向某个方向。现在,如果你想要知道这些苹果有多相似,你可以检查它们箭头之间的角度。当你想要知道事物在一般意义上的对齐程度时,比如找到相似的图片或根据你过去的购买推荐相关产品时,就会使用它。
注意:pgvector 本身并不直接提供基于内积或余弦距离的内置搜索。然而,它以不同的方式利用 L2 距离来实现类似的结果。
pgvector 中的索引:
pgvector 提供两种类型的索引,都是近似最近邻(ANN)索引,用于加速搜索相似向量。选择正确的索引取决于几个因素。以下是它们的关键差异:
特征:将向量空间划分为分区,构建类似图结构的相似向量。
构建时间:显著更快,显著更慢。
内存使用:较少内存,更多内存。
准确性:通常对高维向量不太准确,尤其是对于高维向量,通常具有更好的准确性。
适应性:可能不适用于所有向量分布,很好地处理各种向量分布。
理解 IVFFlat 和 HNSW 的真实世界示例:
想象你住在一个城市,需要找到一个与你喜欢的餐厅相似的餐厅(一个“最近邻”)。
IVFFlat 就像有一张带有标签的社区地图。
根据一般特征将城市划分为不同的区域。
可以快速告诉你哪些社区可能有类似的餐厅。
引导你到那些社区内的餐厅,可能接近,但不一定是每个方面都最相似的。
快速开始使用地图(更快的索引构建)。
需要较少的内存来存储地图。
HNSW 就像有一个了解城市的当地向导。
了解城市如何连接餐厅(相似的口味、氛围等)。
可以快速引导你到在整体体验上接近你最喜欢的餐厅的餐厅,即使它们不完全相同。
需要向导花更多时间了解城市(构建索引)。
需要向导记住更多信息(更高的内存使用)。
选择正确的方法取决于你的优先级:HNSW 就像向导,优先找到最相似的餐厅,即使需要更长的时间。速度:IVFFlat 就像地图,专注于快速找到类似的餐厅,即使它不是完美的。HNSW 适用于复杂的城市布局(高维数据),而 IVFFlat 适用于大城市(大型数据集)。
数据嵌入过程
要创建向量数据,我们首先需要生成它。创建向量数据的过程称为嵌入,它就像一种秘密语言,弥合了计算机数字形式的单词、图像或声音世界之间的差距。
收集数据:想象一个满是书籍的书架,一个充满艺术作品的艺术画廊,或者一起播放的一堆旋律。当我们开始嵌入时,意味着我们正在收集我们想要以向量形式展示的基本元素。
选择嵌入模型:有不同类型的嵌入模型可用于特定类型的信息。一些常见的模型包括:
HuggingFace 或 OpenAI 的 text-embedding-ada-002 用于文本
VGG16 或 ResNet50 用于图像
Audio2Vec 用于声音
训练模型:这就是魔法发生的地方!模型分析数据,识别模式、关系和隐藏的含义。它将单词、图像或声音映射到它们对应的向量,为每一个创建独特的数值表示。
生成向量:一旦模型学会了数据的语言,它就可以根据需求将新输入转换为向量。
HuggingFace 或 OpenAI 嵌入模型 - 如何选择?
选择 Hugging Face 和 OpenAI 来满足您的嵌入需求取决于几个因素:
Hugging Face:侧重于广度和灵活性,提供广泛的自然语言处理模型,用于各种任务。大多数模型都是免费的,某些特定模型或 API 可能需要付费。易于使用,有工具和社区支持。开源工具提供更多控制,但对模型定制的控制较少。
OpenAI:专注于高性能嵌入模型,提供专门化的嵌入模型。通过计划访问,需要付费。API 或 Hugging Face 模型中心访问,对模型定制的控制较少。
最终,最佳选择取决于您的具体需求、预算和技术专长。在做出决定之前,仔细考虑您的优先事项,并比较可用的选项。
利用 pgvector:实际示例
想象一个场景,我们在数据库中以向量形式存储各种单词。然后我们提供不同的单词给数据库,以找到最相似的单词。
我们将存储在数据库中的单词是 Apple、Banana、Cat 和 Dog。我们要搜索的单词是 Mango 和 Horse。
创建扩展:
一旦您在计算机上安装了 pgvector,首先需要创建所需的扩展。
创建表:
为了存储向量数据:
生成嵌入:
我们将使用 HuggingFace 来生成我们的嵌入。
安装所需的 Python 包:
Python 代码以从 langchain 生成嵌入:
这里使用的模型是 all-MiniLM-L6-v2。
下面的图表显示了单词 Apple 的嵌入。
将数据插入数据库:
将 Your_Apple_Embedding 替换为上面图表中显示的原始嵌入。
类似地,我们将插入其他向量,即 Banana、Cat 和 Dog。
插入所有关键词后,我们可以检查 items 表中的行数。
向量搜索:
为了找到一个单词,我们将再次为该单词创建嵌入,并利用生成的嵌入在数据库中搜索该单词。
将生成的 Mango 嵌入插入到下面的查询中以获取结果:
SELECT 查询结构解析:
SELECT name
:这从 items 表中选择项目的名称。1 - (embedding <-> '<Horse_embedding>') AS cosine_similarity
:这个表达式计算每个项目的嵌入与指定的“Horse”嵌入之间的余弦相似度,并将结果别名为 cosine_similarity 列。embedding <-> '<Horse_embedding>'
:这个操作符计算两个向量之间的余弦相似度。它将每个项目的嵌入(存储在 embedding 列中)与“Horse”嵌入的占位符进行比较。1 – …
:相似度计算的结果从 1 中减去,以反转比例,使更高的值代表更大的相似性。ORDER BY cosine_similarity DESC
:这根据计算出的余弦相似度以降序排序结果。这将最相似于“Horse”的项目放在顶部。LIMIT 2
:这限制输出仅为基于计算出的余弦相似度的前两个最相似的项目。
结果分析:
Mango 和 horse 并不直接出现在表中:如果它们在表中列出,那么将返回完美的匹配(余弦相似度为 1)。Banana 和 Apple 对 Mango 有适度的语义相似性。Banana(0.5249995745718354)是最相似的,但不是完全匹配。Apple(0.4006202280151715)的相似度较低,表明关系较弱。Dog 和 Cat 对 Horse 有适度的语义相似性。Dog(0.5349170288394121)是最相似的,但不是完全匹配。Cat(0.41092748143620783)的相似度较低,表明关系较弱。值得注意的是,余弦相似度的范围是从 0 到 1,1 表示完全匹配,意味着项目在用于比较的表示方面是相同的。0 表示完全不相似,意味着项目在它们的表示中没有任何重叠。介于 0 和 1 之间的值代表不同程度的相似性。
在线使用 pgvector:https://cloud.memfiredb.com/auth/login?from=6XLldw
原文:AI Meets PostgreSQL - The pgvector Revolution in Text Search - Stormatics
评论