本教程演示了如何使用 Spanner 和 Vertex AI 构建生成式 AI 应用。
此应用可让您执行语义相似度搜索,从而找到与自然语言查询匹配的商品。为此,它会使用嵌入,即文本的数值表示法,用于捕获字词的含义和上下文。您将使用 Vertex AI 模型生成这些嵌入,然后在 Spanner 中存储和搜索这些嵌入。这种方法对于产品搜索等用例特别有用,在这些用例中,用户可能会使用自然语言而非特定关键字来描述自己想要的内容。
以下主题可帮助您了解如何:
- 创建 Google Cloud 项目
- 创建 Spanner 实例
- 创建数据库
- 创建嵌入模型
- 将数据加载到 Spanner 中
- 为数据生成嵌入
- 执行 KNN 向量相似度搜索
- 使用向量索引大规模执行向量搜索
- 清理资源
如需了解 Spanner 价格详情,请参阅 Spanner 价格。
如需试用 Codelab,请参阅 Spanner 向量搜索使用入门。
准备工作
您必须创建一个与结算账号相关联的 Google Cloud 项目。
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verify that billing is enabled for your Google Cloud project.
- Spanner API 应自动启用。如果未启用,请手动启用: 启用 Spanner API
- Vertex AI API 应自动启用。如果未启用,请手动启用: 启用 Vertex AI API
-
如需获得创建实例和数据库所需的权限,请让您的管理员为您授予项目的 Cloud Spanner Admin (
roles/spanner.admin
) IAM 角色。 -
如需获得查询 Spanner Graph 所需的权限(如果您未获得 Cloud Spanner Admin 角色),请让您的管理员为您授予项目的 Cloud Spanner Database Reader (
roles/spanner.databaseReader
) IAM 角色。 在 Google Cloud 控制台中,前往 Spanner 页面。
选择或创建 Google Cloud 项目(如果尚未创建)。
执行下列其中一项操作:
- 如果您之前未创建过 Spanner 实例,请在欢迎使用 Spanner 页面上点击创建预配实例。
- 如果您已创建 Spanner 实例,请在实例页面上点击创建实例。
在选择版本页面上,选择企业 Plus 版或企业版。
Spanner 向量搜索仅适用于企业版或企业 Plus 版。如需比较不同版本,请点击版本对比。如需了解详情,请参阅 Spanner 版本概览。
点击继续。
在实例名称中,输入一个实例名称,例如
test-instance
。在实例 ID 中,保留或更改实例 ID。您的实例 ID 默认与实例名称相同,但您可以更改它。您的实例名称和实例 ID 可以相同,也可以不同。
点击继续。
在选择配置中,执行以下操作:
- 保持区域级处于选中状态。
- 在选择配置中,选择一个区域。您选择的区域是实例的存储和复制位置。
- 点击继续。
在配置计算容量中,执行以下操作:
- 在选择单位中,选择处理单元 (PU)。
- 在选择伸缩模式中,保持手动分配处于选中状态,并在数量中保留 1000 个处理单元。
点击创建。 Google Cloud 控制台将显示您创建的实例的概览页面。
在 Google Cloud 控制台中,前往 Spanner 实例页面。
点击您创建的实例,例如
test-instance
。在概览中,点击实例名称下方的创建数据库。
在数据库名称中,输入数据库名称。例如
example-db
。在选择数据库方言中,选择 Google 标准 SQL。
PostgreSQL 方言不支持 Spanner 矢量搜索。
将以下架构复制并粘贴到 DDL 模板编辑器标签页中。 该架构定义了一个
Products
表。CREATE TABLE products ( categoryId INT64 NOT NULL, productId INT64 NOT NULL, productName STRING(MAX) NOT NULL, productDescription STRING(MAX) NOT NULL, productDescriptionEmbedding ARRAY<FLOAT32>, createTime TIMESTAMP NOT NULL OPTIONS ( allow_commit_timestamp = true ), inventoryCount INT64 NOT NULL, priceInCents INT64, ) PRIMARY KEY(categoryId, productId);
请勿在显示加密选项中进行任何更改。
点击创建。 Google Cloud 控制台将显示您创建的数据库的概览页面。
- 在数据库概览页面中,点击 Spanner Studio。
- 在 Spanner Studio 页面上,点击 新标签页或使用空白编辑器标签页。
请输入:
CREATE MODEL EmbeddingsModel INPUT( content STRING(MAX), ) OUTPUT( embeddings STRUCT<values ARRAY<FLOAT32>>, ) REMOTE OPTIONS ( endpoint = '//aiplatform.googleapis.com/projects/PROJECT_ID/locations/us-central1/publishers/google/models/TEXT_EMBEDDING_MODEL' );
替换以下内容:
- PROJECT_ID:在您的Google Cloud 项目中唯一的永久性标识符。
- TEXT_EMBEDDING_MODEL:文本嵌入模型的名称。 如需查看 Vertex AI 文本嵌入模型列表,请参阅支持的模型。
点击运行以创建模型。
成功添加模型后,您会在探索器窗格中看到该模型。
在 Spanner Studio 的新标签页中,复制并粘贴以下 insert 语句:
INSERT INTO products (categoryId, productId, productName, productDescription, createTime, inventoryCount, priceInCents) VALUES (1, 1, "Cymbal Helios Helmet", "Safety meets style with the Cymbal children's bike helmet. Its lightweight design, superior ventilation, and adjustable fit ensure comfort and protection on every ride. Stay bright and keep your child safe under the sun with Cymbal Helios!", PENDING_COMMIT_TIMESTAMP(), 100, 10999), (1, 2, "Cymbal Sprout", "Let their cycling journey begin with the Cymbal Sprout, the ideal balance bike for beginning riders ages 2-4 years. Its lightweight frame, low seat height, and puncture-proof tires promote stability and confidence as little ones learn to balance and steer. Watch them sprout into cycling enthusiasts with Cymbal Sprout!", PENDING_COMMIT_TIMESTAMP(), 10, 13999), (1, 3, "Cymbal Spark Jr.", "Light, vibrant, and ready for adventure, the Spark Jr. is the perfect first bike for young riders (ages 5-8). Its sturdy frame, easy-to-use brakes, and puncture-resistant tires inspire confidence and endless playtime. Let the spark of cycling ignite with Cymbal!", PENDING_COMMIT_TIMESTAMP(), 34, 13900), (1, 4, "Cymbal Summit", "Conquering trails is a breeze with the Summit mountain bike. Its lightweight aluminum frame, responsive suspension, and powerful disc brakes provide exceptional control and comfort for experienced bikers navigating rocky climbs or shredding downhill. Reach new heights with Cymbal Summit!", PENDING_COMMIT_TIMESTAMP(), 0, 79999), (1, 5, "Cymbal Breeze", "Cruise in style and embrace effortless pedaling with the Breeze electric bike. Its whisper-quiet motor and long-lasting battery let you conquer hills and distances with ease. Enjoy scenic rides, commutes, or errands with a boost of confidence from Cymbal Breeze!", PENDING_COMMIT_TIMESTAMP(), 72, 129999), (1, 6, "Cymbal Trailblazer Backpack", "Carry all your essentials in style with the Trailblazer backpack. Its water-resistant material, multiple compartments, and comfortable straps keep your gear organized and accessible, allowing you to focus on the adventure. Blaze new trails with Cymbal Trailblazer!", PENDING_COMMIT_TIMESTAMP(), 24, 7999), (1, 7, "Cymbal Phoenix Lights", "See and be seen with the Phoenix bike lights. Powerful LEDs and multiple light modes ensure superior visibility, enhancing your safety and enjoyment during day or night rides. Light up your journey with Cymbal Phoenix!", PENDING_COMMIT_TIMESTAMP(), 87, 3999), (1, 8, "Cymbal Windstar Pump", "Flat tires are no match for the Windstar pump. Its compact design, lightweight construction, and high-pressure capacity make inflating tires quick and effortless. Get back on the road in no time with Cymbal Windstar!", PENDING_COMMIT_TIMESTAMP(), 36, 24999), (1, 9,"Cymbal Odyssey Multi-Tool","Be prepared for anything with the Odyssey multi-tool. This handy gadget features essential tools like screwdrivers, hex wrenches, and tire levers, keeping you ready for minor repairs and adjustments on the go. Conquer your journey with Cymbal Odyssey!", PENDING_COMMIT_TIMESTAMP(), 52, 999), (1, 10,"Cymbal Nomad Water Bottle","Stay hydrated on every ride with the Nomad water bottle. Its sleek design, BPA-free construction, and secure lock lid make it the perfect companion for staying refreshed and motivated throughout your adventures. Hydrate and explore with Cymbal Nomad!", PENDING_COMMIT_TIMESTAMP(), 42, 1299);
点击运行以插入数据。
在 Spanner Studio 的新标签页中,复制并粘贴以下更新语句:
UPDATE products p1 SET productDescriptionEmbedding = (SELECT embeddings.values FROM ML.PREDICT(MODEL EmbeddingsModel, (SELECT p1.productDescription as content) ) ) WHERE categoryId=1;
点击运行以生成嵌入。
- 使用
ML.PREDICT
为给定的搜索查询(“我想为 3 岁的孩子买一辆入门级自行车”)生成嵌入。 - 计算此查询嵌入与商品表中每个商品的
productDescriptionEmbedding
之间的COSINE_DISTANCE
,以在您的 Cymbal 商店中找到类似的结果。 - 过滤结果,以仅包含
inventoryCount
大于 0 的商品。 - 按计算出的距离对结果进行排序,并返回前 5 个最接近的匹配项,以及
productName
、productDescription
和inventoryCount
。 在 Spanner Studio 的新标签页中,复制并粘贴以下查询:
SELECT productName, productDescription, inventoryCount, COSINE_DISTANCE( productDescriptionEmbedding, ( SELECT embeddings.values FROM ML.PREDICT( MODEL EmbeddingsModel, (SELECT "I'd like to buy a starter bike for my 3 year old child" AS content)) )) AS distance FROM products WHERE inventoryCount > 0 ORDER BY distance LIMIT 5;
点击运行,系统会返回与您的搜索文字最匹配的商品。
输出示例:
/*-----------------+--------------------+----------------+--------------------* | productName | productDescription | inventoryCount | distance | +------------------+--------------------+----------------+--------------------+ | Cymbal Sprout | Let their cycling | 10 | 0.3094387191860244 | | | journey begin with | | | | | the Cymbal Sprout, | | | | | the ideal balance | | | | | bike for beginning | | | | | riders ages 2-4 | | | | | years... | | | | Cymbal Spark Jr | Light, vibrant, | 34 | 0.3412342902117166 | | | and ready for | | | | | adventure, the | | | | | Spark Jr. is the | | | | | perfect first bike | | | | | for young riders | | | | | (ages 5-8)... | | | | Cymbal Helios | Safety meets style | 100 | 0.4197863319656684 | | Helmet | with the Cymbal | | | | | children's bike | | | | | helmet... | | | | Cymbal Breeze | Cruise in style and| 72 | 0.485231776523978 | | | embrace effortless | | | | | pedaling with the | | | | | Breeze electric | | | | | bike... | | | | Cymbal Phoenix | See and be seen | 87 | 0.525101413779242 | | Lights | with the Phoenix | | | | | bike lights... | | | *------------------+--------------------+----------------+--------------------*/
在 Spanner Studio 的新标签页中,复制并粘贴以下 DDL 语句以重新创建
productDescriptionEmbedding
列:ALTER TABLE products DROP COLUMN productDescriptionEmbedding; ALTER TABLE products ADD COLUMN productDescriptionEmbedding ARRAY<FLOAT32>(vector_length=>VECTOR_LENGTH_VALUE);
将
VECTOR_LENGTH_VALUE
替换为您选择的嵌入模型的最大输出维度。点击运行。
复制并粘贴以下 insert 语句以重新生成向量嵌入:
UPDATE products p1 SET productDescriptionEmbedding = (SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel, (SELECT p1.productDescription as content))) WHERE categoryId=1;
点击运行。
复制并粘贴以下 DDL 语句以创建向量索引:
CREATE VECTOR INDEX ProductDescriptionEmbeddingIndex ON products(productDescriptionEmbedding) WHERE productDescriptionEmbedding IS NOT NULL OPTIONS ( distance_type = 'COSINE' );
点击运行。
- 单独生成提示嵌入内容,而不是在 SQL 查询中生成。
- 将嵌入的结果复制到查询中。
- 使用
FORCE_INDEX
提示来引用新的向量索引:@{force_index=ProductDescriptionEmbeddingIndex}
- 请使用
APPROX_COSINE_DISTANCE
向量距离函数,而不是COSINE_DISTANCE
。必须提供JSON '{"num_leaves_to_search": num_leaves}'
选项。 在 Spanner Studio 的新标签页中,复制并粘贴以下查询以生成提示嵌入:
-- Generate the prompt embedding SELECT embeddings.values FROM ML.PREDICT( MODEL EmbeddingsModel, (SELECT "I'd like to buy a starter bike for my 3 year old child" as content) );
点击运行。
复制
embeddings.values
结果。将以下查询中的
embedding
替换为您在上一步中复制的嵌入结果。-- Update embedding query using the vector index SELECT productName, productDescription, inventoryCount, (APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[embedding], options => JSON '{\"num_leaves_to_search\": 10}')) as distance FROM products @{force_index=ProductDescriptionEmbeddingIndex} WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0 ORDER BY distance LIMIT 5;
新的 SQL 查询类似于以下内容:
SELECT productName, productDescription, count, (APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[-0.00457216799,-0.0771846101,-0.0319350846,0.0352052487,-0.0457422845,0.0183265656...], options => JSON '{\"num_leaves_to_search\": 10}')) as distance FROM products @{force_index=ProductDescriptionEmbeddingIndex} WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0 ORDER BY distance LIMIT 5;
输出示例:
/*-----------------+--------------------+----------------+--------------------* | productName | productDescription | inventoryCount | distance | +------------------+--------------------+----------------+--------------------+ | Cymbal Sprout | Let their cycling | 10 | 0.30935457151661594| | | journey begin with | | | | | the Cymbal Sprout, | | | | | the ideal balance | | | | | bike for beginning | | | | | riders ages 2-4 | | | | | years... | | | | Cymbal Spark Jr | Light, vibrant, | 34 | 0.34116496551593656| | | and ready for | | | | | adventure, the | | | | | Spark Jr. is the | | | | | perfect first bike | | | | | for young riders | | | | | (ages 5-8)... | | | | Cymbal Helios | Safety meets style | 100 | 0.4198014303921187 | | Helmet | with the Cymbal | | | | | children's bike | | | | | helmet... | | | | Cymbal Breeze | Cruise in style and| 72 | 0.4850674854267337 | | | embrace effortless | | | | | pedaling with the | | | | | Breeze electric | | | | | bike... | | | | Cymbal Phoenix | See and be seen | 87 | 0.525101413779242 | | Lights | with the Phoenix | | | | | bike lights... | | | *------------------+--------------------+----------------+--------------------*/
Cymbal Sprout 的
APPROX_COSINE_DISTANCE
为 0.30935457151661594,与原始查询的相似度最高。如需详细了解如何解读向量函数与相似度之间的关系,请参阅选择向量距离函数来衡量向量嵌入的相似度。
在 Google Cloud 控制台中,前往 Spanner 实例页面。
点击包含要删除的数据库的实例的名称,例如 test-instance。
点击要删除的数据库的名称,例如 example-db。
在数据库概览页面上,点击删除数据库。
输入数据库名称,然后点击删除,确认您要删除该数据库。
在 Google Cloud 控制台中,前往 Spanner 实例页面。
点击要删除的实例的名称,例如 test-instance。
点击删除实例。
输入实例名称,然后点击删除,确认您要删除该实例。
- 详细了解 Spanner 的 K 最近邻 (KNN) 功能。
- 详细了解 Spanner 的近似最近邻 (ANN) 功能。
- 详细了解如何使用 Vertex AI 通过 SQL 执行在线预测。
创建实例
在首次使用 Spanner 时,必须创建一个实例,实例是 Spanner 数据库使用的资源分配单位。本部分介绍如何使用 Google Cloud 控制台创建实例。
创建数据库
实例开始运行后,您就可以创建数据库了。您可以在数据库中定义架构。
创建嵌入模型
在 Spanner 中使用 CREATE MODEL
DDL 语句时,您是在数据库中注册对 Vertex AI 模型端点的引用。注册模型后,您可以使用 ML.PREDICT
函数在查询中访问该模型。
以下示例演示了如何注册 Vertex AI 文本嵌入模型,然后使用该模型执行相似度搜索,以在数据库中查找类似产品。
加载数据
如需将 Cymbal 示例数据加载到 products
表中,请执行以下操作:
生成向量嵌入
注册模型并将数据加载到 Spanner 中后,您可以使用数据中的商品说明生成向量嵌入。 向量嵌入可将文本数据转换为数值,从而捕获字词的含义和上下文。这种转换对于执行语义搜索至关重要。
在此步骤中,您将使用 ML.PREDICT
从 productDescription
列生成嵌入,以填充 productDescriptionEmbedding
列。这样一来,您就可以在下一步中执行向量相似度搜索。
执行向量相似度搜索
在以下示例中,您使用 SQL 查询提供自然语言搜索请求。该 SQL 查询使用您之前生成的向量嵌入执行向量相似度搜索。该查询通过执行以下操作来执行搜索:
扩展向量搜索以使用近似最近邻
之前的向量搜索示例使用的是精确的 K 最近邻 (KNN) 向量搜索。如果您可以查询 Spanner 数据的特定子集,KNN 向量距离函数(余弦距离、欧几里德距离和点积)会很有用。由于 KNN 搜索会计算查询向量与数据库中所有向量之间的确切距离,因此当您可以对数据进行分区时,它会非常高效。如果您的查询需要将查询向量与数据库中的所有向量进行比较,而没有任何特定过滤条件,并且您无法将查询划分为独立的子查询,那么在使用 KNN 时可能会遇到性能瓶颈。在这些情况下,近似最近邻 (ANN) 向量搜索会非常有用。如需了解详情,请参阅查找近似最近邻项。
如果您的工作负载无法进行分区,并且您有大量数据,则可以使用 ANN 向量搜索来提高大型数据集的查询性能。
如需在 Spanner 中扩缩并使用 ANN 向量搜索,请执行以下操作:
创建矢量索引
Spanner 使用利用 Google Research 的可扩容最近邻 (ScaNN) 的专用向量索引来加快 ANN 向量搜索的速度。
如需在数据集中创建向量索引,您需要修改 productDescriptionEmbeddings
列以定义 vector_length
注解。vector_length
注解表示每个向量的维度。以下 DDL 语句会删除 productDescriptionEmbedding
列,并使用 vector_length
重新创建该列。向量的最大长度(维度)因您选择的嵌入模型而异。
使用 ANN 向量距离函数
如需在 Spanner 中使用 ANN 向量搜索,请在 SQL 查询中修改以下内容:
清理
本部分介绍如何使用 Google Cloud 控制台清理资源。为避免您的 Cloud Billing 账号产生额外费用,请删除您在设置过程中创建的数据库和实例。删除实例会删除在该实例中创建的所有数据库。