探索PostgreSQL:从入门到向量数据库的扩展

发表时间: 2023-12-27 17:15

了解如何使用 PostgreSQL 作为矢量数据库来构建和扩展示例 Airbnb 推荐服务。

PostgreSQL 拥有丰富的扩展和解决方案生态系统,让我们可以将数据库用于通用 AI 应用程序。本指南将指导您完成使用 PostgreSQL 作为矢量数据库构建生成式 AI 应用程序所需的步骤。

我们将从 pgvector 扩展开始,它使 Postgres 具有特定于矢量数据库的功能。然后,我们将回顾增强在 PostgreSQL 上运行的 AI 应用程序的性能和可扩展性的方法。最后,我们将拥有一个功能齐全的生成式AI应用程序,向前往旧金山的旅行者推荐Airbnb房源。

Airbnb推荐服务

示例应用程序是住宿推荐服务。想象一下,您计划访问旧金山,并希望住在金门大桥附近的一个不错的街区。您转到服务,输入提示,该应用程序将建议三个最相关的住宿选项。

该应用程序支持两种不同的模式:

  • OpenAI 聊天模式:在此模式下,Node.js 后端利用 OpenAI 聊天完成 API 和 GPT-4 模型根据用户的输入生成住宿建议。虽然此模式不是本指南的重点,但鼓励您尝试一下。
  • Postgres 嵌入模式:最初,后端使用 OpenAI 嵌入 API 将用户的提示转换为嵌入(文本数据的矢量化表示)。接下来,应用在 Postgres 或 YugabyteDB(分布式 PostgreSQL)中执行相似性搜索,以查找与用户提示匹配的 Airbnb 属性。Postgres 利用 pgvector 扩展在数据库中进行相似性搜索。本指南将深入探讨此特定模式在应用程序中的实现。

先决条件

  • 有权访问嵌入模型的 OpenAI 订阅。
  • 最新的 Node.js 版本
  • 最新版本的 Docker

使用 pgvector 启动 PostgreSQL

pgvector 扩展为 Postgres 添加了矢量数据库的所有基本功能。它允许您存储和处理具有数千个维度的向量,计算矢量化数据之间的欧几里得距离和余弦距离,并执行精确和近似的最近邻搜索。
1. 在 Docker 中使用 pgvector 启动 Postgres 实例:

docker run --name postgresql \br
    -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=password \br
    -p 5432:5432 \br
    -d ankane/pgvector:latest

2. 连接到数据库容器并打开 psql 会话:

docker exec -it postgresql psql -h 127.0.0.1 -p 5432 -U postgres

3. 启用 pgvector 扩展:

SQL算法

create extension vector;

4. 确认扩展列表中存在该向量:

SQL算法

select * from pg_extension;br
br
  oid  | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extconditionbr
-------+---------+----------+--------------+----------------+------------+-----------+--------------br
 13561 | plpgsql |       10 |           11 | f              | 1.0        |           |br
 16388 | vector  |       10 |         2200 | t              | 0.5.1      |           |br
(2 rows)

加载 Airbnb 数据集

该应用程序使用Airbnb数据集,该数据集在旧金山列出了7,500多处待出租的房产。每个列表都提供详细的属性描述,包括房间数量、设施类型、位置和其他功能。此信息非常适合针对用户提示进行相似性搜索。

按照以下步骤将数据集加载到已启动的 Postgres 实例中:

1. 克隆应用程序存储库:

git clone https://github.com/YugabyteDB-Samples/openai-pgvector-lodging-service.git

2. 将 Airbnb 架构文件复制到 Postgres 容器(替换为应用程序目录的完整路径):{app_dir}

docker cp {app_dir}/sql/airbnb_listings.sql postgresql:/home/airbnb_listings.sql

3. 从下面的 Google Drive 位置下载包含 Airbnb 数据的文件。文件大小为 174MB,只要它已经包含使用 OpenAI 嵌入模型为每个 Airbnb 属性的描述生成的嵌入。

4. Copy the dataset to the Postgres container (replace the with the full path to the application directory).{data_file_dir}

Shell

docker cp {data_file_dir}/airbnb_listings_with_embeddings.csv postgresql:/home/airbnb_listings_with_embeddings.csv

5. Create the Airbnb schema and load the data into the database:

Shell

# Create schemabr
docker exec -it postgresql \br
    psql -h 127.0.0.1 -p 5432 -U postgres \br
    -a -q -f /home/airbnb_listings.sqlbr
    br
# Load databr
docker exec -it postgresql \br
    psql -h 127.0.0.1 -p 5432 -U postgres \br
    -c "\copy airbnb_listing from /home/airbnb_listings_with_embeddings.csv with DELIMITER '^' CSV;"

每个 Airbnb 嵌入都是一个 1536 维的浮点数数组。它是 Airbnb 房源描述的数字/数学表示。

docker exec -it postgresql \br
    psql -h 127.0.0.1 -p 5432 -U postgres \br
    -c "\x on" \br
    -c "select name, description, description_embedding from airbnb_listing limit 1"br
    br
  br
# Truncated outputbr
name                 | Monthly Piravte Room-Shared Bath near Downtown !3br
description           | In the center of the city in a very vibrant neighborhood. Great access to other parts of the city with all modes of public transportation steps away Like the general theme of San Francisco, our neighborhood is a melting pot of different people with different lifestyles ranging from homeless people to CEO''sbr
description_embedding | [0.0064848186,-0.0030366974,-0.015895316,-0.015803888,-0.02674906,-0.0083198985,-0.0063770646,0.010318241,-0.011003947,-0.037981577,-0.008783566,-0.0005710134,-0.0028015983,-0.011519859,-0.02011404,-0.02023159,0.03325347,-0.017488765,-0.014902675,-0.006527267,-0.027820067,0.010076611,-0.019069154,-0.03239144,-0.013243919,0.02170749,0.011421901,-0.0044701495,-0.0005861153,-0.0064978795,-0.0006775427,-0.018951604,-0.027689457,-0.00033081227,0.0034317947,0.0098349815,0.0034775084,-0.016835712,-0.0013787586,-0.0041632145,-0.0058219694,-0.020584237,-0.007386032,0.012486378,0.012473317,0.005815439,-0.010990886,-0.015111651,-0.023366245,0.019069154,0.017828353,0.030249426,-0.04315376,-0.01790672,0.0047444315,-0.0053419755,-0.02195565,-0.0057338076,-0.02576948,-0.009769676,-0.016914079,-0.0035232222,... 

嵌入是使用 OpenAI 的模型生成的。如果需要使用其他模型,则:text-embedding-ada-002

  • 更新 and 文件中的模型{app_dir}/backend/embeddings_generator.js{app_dir}/backend/postgres_embeddings_service.js
  • 通过使用命令启动生成器来重新生成嵌入。node embeddings_generator.js

查找最相关的 Airbnb 房源

至此,Postgres已准备好向用户推荐最相关的Airbnb属性。应用程序可以通过将用户的提示嵌入与 Airbnb 描述的嵌入进行比较来获取这些建议。

首先,启动 Airbnb 推荐服务的实例:

1. 使用您的 OpenAI API 密钥进行更新:{app_dir}
/application.properties.ini

OPENAI_API_KEY=<your key>

2. 启动 Node.js 后端:

cd {app_dir}br
npm i br
cd backendbr
npm start

3. 启动 React 前端:

cd {app_dir}/frontendbr
npm ibr
npm start

应用程序 UI 应在默认浏览器中自动打开。否则,请在地址 http://localhost:3000/

现在,从应用程序 UI 中选择 Postgres 嵌入模式,并要求应用程序推荐一些与以下提示最相关的 Airbnb 房源:

I'm looking for an apartment near the Golden Gate Bridge with a nice view of the Bay.

该服务将推荐三种住宿选择:

在内部,应用程序执行以下步骤来生成建议(有关详细信息,请参阅):{app_dir}
/backend/postgres_embeddings_service.js

1. 应用程序使用 OpenAI 嵌入模型生成用户提示的矢量化表示 ():text-embedding-ada-002

JavaScript的

const embeddingResp = await this.#openai.embeddings.create(br
    {model: "text-embedding-ada-002",br
    input: prompt});

2. 该应用程序使用生成的向量来检索存储在 Postgres 中的最相关的 Airbnb 属性:

JavaScript的

const res = await this.#client.query(br
    "SELECT name, description, price, 1 - (description_embedding <=> $1) as similarity " +br
    "FROM airbnb_listing WHERE 1 - (description_embedding <=> ) >  ORDER BY description_embedding <=>  LIMIT ",br
    ['[' + embeddingResp.data[0].embedding + ']', matchThreshold, matchCnt]);

相似度计算为列中存储的嵌入与用户提示向量之间的余弦距离。description_embedding

3. 建议的 Airbnb 属性以 JSON 格式返回到 React 前端:

JavaScript的

let places = [];br
br
for (let i = 0; i < res.rows.length; i++) {br
    const row = res.rows[i];br
    places.push({br
      "name": row.name, br
      "description": row.description, br
      "price": row.price, br
      "similarity": row.similarity });br
}br
br
return places;

扩展方式

目前,Postgres存储了超过7,500个Airbnb属性。数据库需要几毫秒才能执行精确的最近邻搜索,比较用户提示和 Airbnb 描述的嵌入。

但是,精确的最近邻搜索(全表扫描)有其局限性。随着数据集的增长,Postgres 需要更长的时间才能对多维向量执行相似性搜索。

为了在不断增加的数据量和流量中保持 Postgres 的性能和可扩展性,您可以使用矢量化数据的专用索引和/或使用分布式版本的 Postgres 水平扩展存储和计算资源。

pgvector 扩展支持多种索引类型,包括性能最佳的 HNSW 索引(分层导航小世界)。此索引对矢量化数据执行近似最近邻搜索 (ANN),使数据库即使在数据量很大的情况下也能保持低且可预测的延迟。但是,由于搜索是近似值,因此搜索的召回可能不是 100% 相关/准确的,因为索引仅遍历数据的子集。

例如,以下是如何在Postgres中为Airbnb嵌入创建HNSW索引:

SQL算法

CREATE INDEX ON airbnb_listingbr
USING hnsw (description_embedding vector_cosine_ops)br
WITH (m = 4, ef_construction = 10);

使用分布式 PostgreSQL,当单个数据库服务器的容量不再足够时,可以轻松扩展数据库存储和计算资源。尽管 PostgreSQL 最初是为单服务器部署而设计的,但其生态系统现在包括多个扩展和解决方案,使其能够在分布式配置中运行。其中一种解决方案是 YugabyteDB,这是一个分布式 SQL 数据库,它扩展了 Postgres 在分布式环境中的功能。

YugabyteDB 从 2.19.2 版本开始支持 pgvector 扩展。它将数据和嵌入分布在节点集群中,从而促进大规模的相似性搜索。因此,如果您希望 Airbnb 服务在 Postgres 的分布式版本上运行:

1. 部署多节点 YugabyteDB 集群。

2. 更新文件中的数据库连接设置:{app_dir}
/application.properties.ini

# Configuration for a locally running YugabyteDB instance with defaults.br
DATABASE_HOST=localhostbr
DATABASE_PORT=5433br
DATABASE_NAME=yugabytebr
DATABASE_USER=yugabytebr
DATABASE_PASSWORD=yugabyte

3. 从头开始加载数据(或使用 YugabyteDB Voyager 从正在运行的 Postgres 实例迁移数据)并重新启动应用程序。不需要其他代码级更改,因为 YugabyteDB 的功能和运行时与 Postgres 兼容。

享受使用 Postgres 构建可扩展 AI 应用程序的乐趣,如果您想了解有关 Postgres 作为矢量数据库的更多信息,请告诉我。


原文标题:PostgreSQL as a Vector Database: Getting Started and Scaling

原文链接:
https://dzone.com/articles/postgresql-vector-database

作者:Denis Magda

编译:LCR