本教學課程說明如何使用 Spanner 和 Vertex AI 建構生成式 AI 應用程式。
這項應用程式可讓您執行語意相似度搜尋,找出符合自然語言查詢的產品。這項技術會使用嵌入項目 (以數字表示文字,並從中捕捉字詞的意義和脈絡),您將使用 Vertex AI 模型生成這些嵌入,然後在 Spanner 中儲存及搜尋嵌入。這種做法特別適合產品搜尋等用途,因為使用者可能會以自然語言描述想要的產品,而不是使用特定關鍵字。
下列主題可協助您瞭解如何:
- 建立 Google Cloud 專案
- 建立 Spanner 執行個體
- 建立資料庫
- 建立嵌入模型
- 將資料載入 Spanner
- 為資料生成嵌入
- 執行 KNN 向量相似度搜尋
- 使用向量索引擴充向量搜尋功能
- 清除資源
如要瞭解 Spanner 定價詳細資料,請參閱 Spanner 定價。
如要試用程式碼研究室,請參閱「開始使用 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 管理員 (
roles/spanner.admin
) 身分與存取權管理角色。 -
如要取得查詢 Spanner 圖表所需的權限 (如果未獲授 Cloud Spanner 管理員角色),請要求管理員授予您專案的 Cloud Spanner 資料庫讀取者 (
roles/spanner.databaseReader
) IAM 角色。 前往 Google Cloud 控制台的「Spanner」頁面。
選取或建立 Google Cloud 專案 (如果尚未建立)。
執行下列其中一個步驟:
- 如果您先前未建立 Spanner 執行個體,請在「Welcome to Spanner」(歡迎使用 Spanner) 頁面上,按一下「Create a provisioned instance」(建立已佈建的執行個體)。
- 如果您已建立 Spanner 執行個體,請在「Instances」(執行個體) 頁面中,按一下「Create instance」(建立執行個體)。
在「選取版本」頁面中,選取「Enterprise Plus」或「Enterprise」。
Spanner 向量搜尋功能僅適用於 Enterprise 版或 Enterprise Plus 版。如要比較不同版本,請按一下「比較版本」。詳情請參閱「Spanner 版本總覽」。
按一下「繼續」。
在「Instance name」(執行個體名稱) 中輸入執行個體名稱,例如
test-instance
。在「Instance ID」(執行個體 ID) 中保留或變更執行個體 ID。執行個體 ID 預設為執行個體名稱,但您可以變更。執行個體名稱和執行個體 ID 可以相同,也可以不同。
按一下「繼續」。
在「選擇設定」中,執行下列操作:
- 請選取「區域」。
- 在「選取設定」中,選取區域。您選取的區域是執行個體的儲存和複製位置。
- 按一下「繼續」。
在「設定運算能力」中,執行下列操作:
- 在「選取單位」中,選取「處理單元 (PU)」。
- 在「選擇調整資源配置模式」中,保留選取的「手動分配」,並在「數量」中保留 1000 個處理單元。
點選「建立」。 Google Cloud 控制台會顯示您所建立執行個體的「總覽」頁面。
前往 Google Cloud 控制台的「Spanner Instances」(Spanner 執行個體) 頁面。
按一下您建立的執行個體,例如
test-instance
。在「總覽」中,按一下執行個體名稱下方的「建立資料庫」。
在「Database name」(資料庫名稱) 中輸入資料庫名稱。例如:
example-db
。在「選取資料庫方言」中,選擇 Google 標準 SQL。
PostgreSQL 方言不支援 Spanner 向量搜尋。
複製下列結構定義,並貼到「DDL Templates」編輯器分頁中。 結構定義會定義
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:專案的專屬永久 ID。Google Cloud
- TEXT_EMBEDDING_MODEL:文字嵌入模型名稱。 如需 Vertex AI 文字嵌入模型清單,請參閱「支援的模型」。
按一下「執行」,建立模型。
成功新增模型後,模型會顯示在「Explorer」窗格中。
在 Spanner Studio 的新分頁中,複製並貼上下列插入陳述式:
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 歲的孩子購買入門腳踏車」) 生成嵌入。 - 計算這項查詢嵌入內容與產品表格中每個產品的
COSINE_DISTANCE
,在 Cymbal 商店中找出類似結果。productDescriptionEmbedding
- 篩選結果,僅納入
inventoryCount
大於 0 的產品。 - 依據計算出的距離排序結果,並傳回最接近的前五個相符項目,以及
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
改成所選嵌入模型可輸出的最大維度。按一下「執行」。
複製並貼上下列插入陳述式,重新產生向量嵌入內容:
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 Instances」(Spanner 執行個體) 頁面。
按一下要刪除資料庫的執行個體名稱,例如 test-instance。
按一下要刪除的資料庫名稱,例如 example-db。
在「資料庫總覽」頁面,按一下「刪除資料庫」。
輸入資料庫名稱,然後按一下「刪除」,確認要刪除資料庫。
前往 Google Cloud 控制台的「Spanner Instances」(Spanner 執行個體) 頁面。
按一下要刪除的執行個體名稱,例如「test-instance」。
按一下 [Delete 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 搜尋的效率很高。如果查詢需要比較查詢向量與資料庫中的所有向量,且沒有任何特定篩選器,而且您無法將查詢劃分為獨立的子查詢,則使用 KNN 時可能會遇到效能瓶頸。在這些情況下,近似近鄰 (ANN) 向量搜尋就派上用場了。詳情請參閱「尋找近似最近鄰」。
如果工作負載無法分割,且資料量龐大,可以使用 ANN 向量搜尋,提升大型資料集的查詢效能。
如要在 Spanner 中調整 ANN 向量搜尋的規模並加以使用,請執行下列操作:
建立向量索引
Spanner 採用專用向量索引,並運用 Google 研究團隊的可擴充最鄰近項目 (ScaNN),加快 ANN 向量搜尋速度。
如要在資料集中建立向量索引,您需要修改 productDescriptionEmbeddings
資料欄,定義 vector_length
註解。vector_length
註解表示每個向量的維度。下列 DDL 陳述式會捨棄 productDescriptionEmbedding
資料欄,並使用 vector_length
重新建立該資料欄。向量的最大長度 (維度) 取決於您選擇的嵌入模型。
使用 ANN 向量距離函式
如要在 Spanner 中使用 ANN 向量搜尋,請在 SQL 查詢中修改下列項目:
清除所用資源
本節說明如何使用 Google Cloud 控制台清除資源。如要避免系統向您的 Cloud Billing 帳戶收取額外費用,請刪除您在設定期間建立的資料庫和執行個體。刪除執行個體時,也會刪除您在其中建立的所有資料庫。