百万向量,零循环:使用 AlloyDB 大规模生成嵌入

1. 概览

在此 Codelab 中,您将构建一个可扩缩的知识库搜索应用。您无需使用 Python 脚本和循环来管理复杂的 ETL 流水线以生成向量嵌入,而是可以使用 AlloyDB AI,通过单个 SQL 命令在数据库中原生处理嵌入生成。

d4324260c68d4a70.png

构建内容

一个高性能的“可搜索”知识库数据库应用。

学习内容

您将学习如何:

  • 预配 AlloyDB 集群并启用 AI 扩展程序。
  • 使用 SQL 生成合成数据(超过 50,000 行)。
  • 使用批处理为整个数据集回填向量嵌入。
  • 设置实时增量触发器,以自动嵌入新数据。
  • 针对“Flexing Context”执行混合搜索(向量 + SQL 过滤条件)。

要求

  • 一个浏览器,例如 Chrome 或 Firefox。
  • 启用了结算功能的 Google Cloud 项目。
  • 基本熟悉 SQL。

2. 准备工作

创建项目

  1. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。
  2. 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能。
  3. 您将使用 Cloud Shell,这是一个在 Google Cloud 中运行的命令行环境。点击 Google Cloud 控制台顶部的“激活 Cloud Shell”。

“激活 Cloud Shell”按钮图片

  1. 连接到 Cloud Shell 后,您可以使用以下命令检查自己是否已通过身份验证,以及项目是否已设置为您的项目 ID:
gcloud auth list
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目。
gcloud config list project
  1. 如果项目未设置,请使用以下命令进行设置:
gcloud config set project <YOUR_PROJECT_ID>
  1. 启用所需的 API:点击链接并启用 API。

或者,您也可以使用 gcloud 命令。如需了解 gcloud 命令和用法,请参阅文档。

gcloud services enable \
  alloydb.googleapis.com \
  compute.googleapis.com \
  cloudresourcemanager.googleapis.com \
  servicenetworking.googleapis.com \
  aiplatform.googleapis.com

注意事项和问题排查

“幽灵项目”综合征

您运行了 gcloud config set project,但实际上在控制台界面中查看的是另一个项目。请检查左上角下拉菜单中的项目 ID!

结算障碍

您启用了项目,但忘记了结算账号。AlloyDB 是一款高性能引擎,如果“油箱”(结算)为空,它将无法启动。

API 传播延迟

您点击了“启用 API”,但命令行仍显示 Service Not Enabled。只需 60 秒,云端需要一点时间来唤醒其神经元。

配额泥潭

如果您使用的是全新的试用账号,则可能会达到 AlloyDB 实例的区域配额。如果 us-central1 失败,请尝试 us-east1。

“隐藏”服务代理

有时,AlloyDB 服务代理不会自动获得 aiplatform.user 角色。如果您的 SQL 查询之后无法与 Gemini 通信,通常就是这个原因。

3. 数据库设置

在本实验中,我们将使用 AlloyDB 作为测试数据的数据库。它使用集群来保存所有资源,例如数据库和日志。每个集群都有一个主实例,用于提供对数据的访问点。表将保存实际数据。

我们来创建一个 AlloyDB 集群、实例和表,用于加载测试数据集。

  1. 点击该按钮,或将以下链接复制到您已登录 Google Cloud 控制台用户的浏览器中。

  1. 完成此步骤后,代码库将被克隆到您的本地 Cloud Shell 编辑器中,您将能够从项目文件夹中运行以下命令(请务必确保您位于项目目录中):
sh run.sh
  1. 现在,使用界面(点击终端中的链接或点击终端中的“在网页上预览”链接)。
  2. 输入您的项目 ID、集群和实例名称等详细信息,即可开始使用。
  3. 在日志滚动时,您可以去喝杯咖啡,也可以点击此处了解系统在后台是如何执行此操作的。此过程可能需要 10-15 分钟。

注意事项和问题排查

“耐心”问题

数据库集群是重型基础设施。如果您刷新页面或终止 Cloud Shell 会话(因为它“看起来卡住了”),您可能会得到一个“幽灵”实例,该实例已部分预配,如果不进行人工干预,则无法删除。

地区不匹配

如果您在 us-central1 中启用了 API,但尝试在 asia-south1 中预配集群,则可能会遇到配额问题或服务账号权限延迟。在整个实验中,请始终使用同一个区域!

僵尸集群

如果您之前为某个集群使用了相同的名称,但未将其删除,则脚本可能会提示该集群名称已存在。集群名称在项目中必须是唯一的。

Cloud Shell 超时

如果您在茶歇时离开 30 分钟,Cloud Shell 可能会进入休眠状态并断开 sh run.sh 进程。请让标签页保持活跃状态!

4. 架构预配

在此步骤中,我们将介绍以下内容:

879263c907f3cac6.png

AlloyDB 集群和实例运行后,前往 AlloyDB Studio SQL 编辑器,启用 AI 扩展程序并预配架构。

1e3ac974b18a8113.png

您可能需要等待实例创建完成。完成后,使用您在创建集群时创建的凭据登录 AlloyDB。使用以下数据向 PostgreSQL 进行身份验证:

  • 用户名:“postgres”
  • 数据库:“postgres”
  • 密码:“alloydb”(或您在创建时设置的任何密码)

成功通过 AlloyDB Studio 身份验证后,您可以在编辑器中输入 SQL 命令。您可以使用最后一个窗口右侧的加号添加多个编辑器窗口。

28cb9a8b6aa0789f.png

您将在编辑器窗口中输入 AlloyDB 命令,并根据需要使用“运行”“格式化”和“清除”选项。

启用扩展程序

为了构建此应用,我们将使用扩展程序 pgvector 和 google_ml_integration。借助 pgvector 扩展程序,您可以存储和搜索向量嵌入。google_ml_integration 扩展程序提供了一些函数,可用于访问 Vertex AI 预测端点,以便在 SQL 中获取预测结果。通过运行以下 DDL 启用这些扩展程序:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

创建表

我们需要一个数据集来演示扩缩。我们将使用 SQL 立即生成 50,000 行合成“帮助文章”,而不是导入 CSV。

您可以在 AlloyDB Studio 中使用以下 DDL 语句创建表:

-- 1. Create the table
CREATE TABLE help_articles (
    id SERIAL PRIMARY KEY,
    title TEXT,
    category TEXT,
    product_version TEXT,
    content_body TEXT,
    embedding vector(768) -- Dimension for text-embedding-005
);

-- 2. Generate 50,000 rows of synthetic data
INSERT INTO help_articles (title, category, product_version, content_body)
SELECT
    'Help Article ' || i,
    CASE 
        WHEN i % 3 = 0 THEN 'Billing' 
        WHEN i % 3 = 1 THEN 'Technical' 
        ELSE 'General' 
    END,
    CASE 
        WHEN i % 2 = 0 THEN '2.0' 
        ELSE '1.0' 
    END,
    'This article covers common issues regarding ' || 
    CASE 
        WHEN i % 3 = 0 THEN 'payment failures, invoice disputes, and credit card updates.'
        WHEN i % 3 = 1 THEN 'connection timeouts, latency issues, and API errors.'
        ELSE 'account profile settings, password resets, and user roles.' 
    END
FROM generate_series(1, 50000) AS i;

item_vector 列将允许存储文本的向量值。

验证数据:

SELECT count(*) FROM help_articles;
-- Output: 50000

启用数据库标志

前往实例配置控制台,点击“修改主实例”,前往“高级配置”,然后点击“添加数据库标志”。

  1. 验证 google_ml_integration.enable_model_support 标志是否已设置为 on:

如果没有,请在标志下拉菜单中输入该标志,将其设置为“ON”,然后更新实例。

  1. 验证 google_ml_integration.enable_faster_embedding_generation 标志是否已设置为 on:

如果没有,请在标志下拉菜单中输入该标志,将其设置为“ON”,然后更新实例。

配置数据库标志的步骤:

  1. 在 Google Cloud 控制台中,前往“集群”页面。

转到集群

  1. 在资源名称列中点击相应集群。
  2. 在概览页面中,前往集群中的实例,选择一个实例,然后点击修改。
  3. 对实例添加、修改或删除数据库标志:

添加标志

  1. 如需向实例添加数据库标志,请点击“添加标志”。
  2. 从“新增数据库标志”列表中选择一个标志。
  3. 为标志提供值。
  4. 点击“完成”。
  5. 点击更新实例。
  6. 验证 google_ml_integration 扩展程序是否为 1.5.2 或更高版本:

您可以使用以下命令查看扩展程序版本:

SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';

如果您需要将扩展程序更新到更高版本,请使用以下命令:

ALTER EXTENSION google_ml_integration UPDATE;

授予权限

  1. 如需允许用户管理自动嵌入生成,请授予对 google_ml.embed_gen_progress 和 google_ml.embed_gen_settings 表的 INSERT、UPDATE 和 DELETE 权限:
GRANT INSERT, UPDATE, DELETE ON google_ml.embed_gen_progress TO postgres;

‘postgres’是获得权限的 USER_NAME。

  1. 运行以下语句,授予对“embedding”函数的执行权限:
GRANT EXECUTE ON FUNCTION embedding TO postgres;

为 AlloyDB 服务账号授予 Vertex AI User 角色

在 Google Cloud IAM 控制台中,向 AlloyDB 服务账号(格式如下:service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com)授予“Vertex AI User”角色。PROJECT_NUMBER 将包含您的项目编号。

或者,您也可以在 Cloud Shell 终端中运行以下命令:

PROJECT_ID=$(gcloud config get-value project)


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

注意事项和问题排查

“密码失忆”循环

如果您使用了“一键式”设置,但忘记了密码,请前往控制台中的“实例基本信息”页面,然后点击“修改”以重置 postgres 密码。

“找不到扩展程序”错误

如果 CREATE EXTENSION 失败,通常是因为实例在初始预配后仍处于“维护”或“更新”状态。请检查实例创建步骤是否已完成,并根据需要等待几秒钟。

5. “一次性”向量生成

这是本实验的核心。我们将使用 ai.initialize_embeddings 函数,而不是编写 Python 循环来处理这 50,000 行。

此单一命令会执行两项操作:

  1. 回填所有现有行。
  2. 创建触发器,以便自动嵌入未来行。

在 AlloyDB 查询编辑器中运行以下 SQL 语句

CALL ai.initialize_embeddings(
  model_id => 'text-embedding-005',
  table_name => 'help_articles',
  content_column => 'content_body',
  embedding_column => 'embedding',
  incremental_refresh_mode => 'transactional'
);

验证嵌入

检查 embedding 列现在是否已填充:

SELECT id, left(content_body, 30), substring(embedding::text, 1, 30) as vector_partial 
FROM help_articles;

您应该会看到类似如下的结果:

a872b8926a164275.png

刚刚发生了什么?

  1. 大规模回填:它会自动扫描现有的 50,000 行,并通过 Vertex AI 生成嵌入。
  2. 自动化:通过设置 incremental_refresh_mode => 'transactional',AlloyDB 会自动设置内部触发器。插入到 help_articles 中的任何新行都会立即生成其嵌入。
  3. 您可以选择设置 incremental_refresh_mode => ‘None',这样您就只能通过该语句执行批量更新,并手动调用 ai.refresh_embeddings() 来更新所有行的嵌入。

您刚刚用 6 行 SQL 替换了 Kafka 队列、Python 工作器和迁移脚本。如需了解所有属性,请参阅详细的官方文档。

实时触发器测试

我们来验证一下“Zero Loop”自动化操作是否适用于新数据。

  1. 插入新行:
INSERT INTO help_articles (title, category, product_version, content_body)
VALUES ('New Scaling Guide', 'Technical', '2.0', 'How to scale AlloyDB to millions of transactions.');
  1. 立即检查:
SELECT embedding FROM help_articles WHERE title = 'New Scaling Guide';

结果:

您应该会看到系统立即生成了向量,而无需运行任何外部脚本。

调优批次大小

目前,AlloyDB 默认批次大小为 50。虽然默认设置开箱即用,但 AlloyDB 仍允许用户根据其独特的模型和数据集进行微调,以实现完美配置。

CALL ai.initialize_embeddings(
  model_id => 'text-embedding-005',
  table_name => 'help_articles',
  content_column => 'content_body',
  embedding_column => 'embedding',
  incremental_refresh_mode => 'transactional',
  batch_size => 20
);

不过,用户需要注意可能会限制性能的配额限制。如需查看建议的 AlloyDB 配额,请参阅文档中的“准备工作”部分。

注意事项和问题排查

IAM 传播延迟

您运行了 gcloud IAM 命令,但 SQL CALL 仍然失败,并出现权限错误。IAM 更改可能需要一些时间才能通过 Google 主干网络传播。深呼吸。

向量维度不匹配

help_articles 表在 content_body 列上设置为 VECTOR(768)。如果您之后尝试使用其他模型(例如 1536 维模型),插入操作将会失败。坚持text-embedding-005。

6. 灵活的上下文搜索

现在,我们执行混合搜索。我们将语义理解(向量)与业务逻辑(SQL 过滤条件)相结合。

运行此查询可查找专门针对产品版本 2.0 的结算问题:

SELECT
  title,
  left(content_body, 100) as content_snippet,
  1 - (embedding <=> embedding('text-embedding-005', 'Invoice did not go through')::vector) as relevance
FROM help_articles
WHERE category = 'Billing'  -- Hard SQL Filter
  AND product_version = '2.0' -- Hard SQL Filter
ORDER BY relevance DESC
LIMIT 5;

这是 Flexing Context。搜索功能会“灵活”理解用户意图(“结算问题”),同时遵守严格的业务限制(版本 2.0)。

f0fdb50d6195c462.png

为何能赢得初创公司和迁移客户

  1. 零基础设施债务:您无需启动单独的向量数据库(Pinecone/Milvus)。您没有编写单独的 ETL 作业。一切都在 Postgres 中。
  2. 实时更新:通过使用“事务”模式,您的搜索索引永远不会过时。数据一经提交,即可进行向量化。
  3. 扩缩:AlloyDB 基于 Google 的基础架构构建。它能够以比 Python 脚本更快的速度批量生成数百万个向量。

注意事项和问题排查

生产环境性能问题

问题:50,000 行数据时速度很快。如果类别过滤条件的选择性不够,则对于 100 万行数据,速度会非常慢。解决方案:添加向量索引:对于生产规模,您必须创建索引:CREATE INDEX ON help_articles USING hnsw (embedding vector_cosine_ops);验证索引使用情况:运行 EXPLAIN ANALYZE SELECT ...,确保数据库使用的是索引,而不是执行顺序扫描。

“模型不匹配”灾难

问题:您在 CALL 过程中使用 text-embedding-005 初始化了该列。如果您在 SELECT 查询函数 embedding('model-name', …) 中不小心使用了其他模型(例如 text-embedding-004 或 OSS 模型),则维度可能匹配 (768),但向量空间会完全不同。查询运行时不会出错,但结果完全不相关(相关性得分毫无意义)。问题排查:确保 ai.initialize_embeddings 中的 model_id 与 SELECT 查询中的 model_id 完全一致。

“静默空”结果(过度过滤)

问题:混合搜索是一种“AND”运算。它需要语义匹配和 SQL 匹配。如果用户搜索“Billing help”,但 product_version 列包含 ‘2.0.1' 而不是 ‘2.0',则结果为零行,即使向量匹配度为 99% 也是如此。问题排查:

  • 先运行不含向量排序的查询,看看 SQL 过滤条件 (WHERE category...) 是否确实返回了数据。
  • 检查大小写区分设置(Billing 与 billing)。

4. 权限/配额错误(500 错误)

问题:SELECT 子句中的 embedding() 函数会向 Vertex AI 发出实时网络调用。如果数据库服务账号失去 Vertex AI User 角色,或者您达到 Vertex AI API 配额 (QPM),整个 SQL 查询都会失败。问题排查:

  • 查看 AlloyDB 的 Cloud Logging。
  • 确保 IAM 角色仍处于有效状态。
  • 如果需要高弹性,请在存储过程中将函数封装在 TRY/CATCH 块中。

5. Null 嵌入

问题:如果您在模型完全初始化之前插入数据,或者后台工作器失败,则某些行的 embedding 列中可能包含 NULL。NULL <=> Vector 会返回 NULL。这些行会从排列顺序中消失。问题排查:

  • 运行 SELECT count(*) FROM help_articles WHERE embedding IS NULL; 以验证是否达到 100% 的覆盖率。

7. 清理

完成本实验后,请务必删除 AlloyDB 集群和实例。

它应该会清理集群及其中的实例。

8. 恭喜

您已成功构建一个可扩缩的知识库搜索应用。您无需使用 Python 脚本和循环来管理复杂的 ETL 流水线以生成向量嵌入,而是使用 AlloyDB AI,通过一条 SQL 命令在数据库中原生处理嵌入生成。

我们的学习内容

  • 我们淘汰了用于数据处理的“Python For 循环”。
  • 我们使用一条 SQL 命令生成了 50,000 个向量。
  • 我们使用触发器实现了未来向量生成的自动化。
  • 我们执行了混合搜索。

后续步骤