開始使用 Spanner Vector Search

1. 簡介

Spanner 是一項全代管的全球分布式資料庫服務,可水平擴充,適合用於關聯和非關聯的作業工作負載。

Spanner 內建向量搜尋支援功能,可讓您在 GenAI 應用程式中大規模執行相似或語意搜尋,並導入檢索增強生成 (RAG) 功能,利用精確的 K 近鄰 (KNN) 或近似近鄰 (ANN) 功能。

與其他作業資料查詢一樣,Spanner 的向量搜尋查詢會在交易完成後立即傳回最新的即時資料。

在本實驗室中,您將逐步設定利用 Spanner 執行向量搜尋所需的基本功能,並使用 SQL 存取 Vertex AI 模型花園中的嵌入和 LLM 模型。

架構如下所示:

d179a760add7adc0.png

有了這個基礎,您將瞭解如何建立由 ScaNN 演算法支援的向量索引,並在語義工作負載需要擴充時使用 APPROX 距離函式。

建構項目

本實驗室的學習內容如下:

  • 可建立 Spanner 執行個體
  • 設定 Spanner 的資料庫結構定義,以便在 Vertex AI 中整合嵌入和 LLM 模型
  • 載入零售資料集
  • 針對資料集發出相似搜尋查詢
  • 為 LLM 模型提供情境,產生特定產品的推薦內容。
  • 修改結構定義並建立向量索引。
  • 變更查詢,以便運用新建立的向量索引。

課程內容

  • 如何設定 Spanner 執行個體
  • 如何整合 Vertex AI
  • 如何使用 Spanner 執行向量搜尋,在零售資料集中找出相似項目
  • 如何準備資料庫,以便使用 ANN 搜尋功能擴大向量搜尋工作負載。

軟硬體需求

  • 已連結至帳單帳戶的 Google Cloud 專案。
  • 網路瀏覽器,例如 ChromeFirefox

2. 設定和需求

建立專案

如果您還沒有 Google 帳戶 (Gmail 或 Google Apps),請務必建立帳戶。登入 Google Cloud Platform 主控台 ( console.cloud.google.com),然後建立新專案。

如果您已有專案,請按一下主控台左上方的專案選取下拉式選單:

6c9406d9b014760.png

然後按一下對話方塊中的「NEW PROJECT」(新專案) 按鈕,建立新專案:

949d83c8a4ee17d9.png

如果您還沒有專案,系統會顯示類似以下的對話方塊,讓您建立第一個專案:

870a3cbd6541ee86.png

在後續的專案建立對話方塊中,您可以輸入新專案的詳細資料:

6a92c57d3250a4b3.png

請記住專案 ID,這是所有 Google Cloud 專案的專屬名稱 (上述名稱已被使用,因此無法使用)。這個值會在本程式碼研究室的後續章節中稱為 PROJECT_ID。

接下來,如果您尚未這樣做,請在開發人員控制台中啟用計費功能,以便使用 Google Cloud 資源並啟用 Spanner API

15d0ef27a8fbab27.png

完成這個程式碼研究室的費用不應超過數美元,但如果您決定使用更多資源,或是將資源繼續執行,則可能會增加費用 (請參閱本文件結尾的「清理」一節)。如要瞭解 Google Cloud Spanner 的定價,請參閱這篇文章

Google Cloud Platform 新使用者享有價值$300 美元的免費試用期,因此您應該可以免費使用本程式碼研究室。

Google Cloud Shell 設定

雖然 Google Cloud 和 Spanner 可透過筆電遠端操作,但在本程式碼研究室中,我們會使用 Google Cloud Shell,這是在 Cloud 中執行的指令列環境。

這種以 Debian 為基礎的虛擬機器,搭載各種您需要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,可大幅提升網路效能和驗證功能。也就是說,您只需要瀏覽器就能使用本程式碼研究室 (是的,在 Chromebook 上也適用)。

  1. 如要在 Cloud 控制台中啟用 Cloud Shell,只要按一下「啟用 Cloud Shell」gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A 即可 (系統只需幾秒鐘的時間就能佈建環境並連線)。

JjEuRXGg0AYYIY6QZ8d-66gx_Mtc-_jDE9ijmbXLJSAXFvJt-qUpNtsBsYjNpv2W6BQSrDc1D-ARINNQ-1EkwUhz-iUK-FUCZhJ-NtjvIEx9pIkE-246DomWuCfiGHK78DgoeWkHRw

Screen Shot 2017-06-14 at 10.13.43 PM.png

連線至 Cloud Shell 後,您應會發現自己通過驗證,且專案已設為您的 PROJECT_ID。

gcloud auth list

指令輸出

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

指令輸出

[core]
project = <PROJECT_ID>

如果因某些原因而未設定專案,請直接發出下列指令:

gcloud config set project <PROJECT_ID>

正在尋找PROJECT_ID嗎?請查看你在設定步驟中使用的 ID,或在 Cloud 控制台資訊主頁中查詢:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell 也會預設設定部分環境變數,這在您日後執行指令時可能會很有用。

echo $GOOGLE_CLOUD_PROJECT

指令輸出

<PROJECT_ID>

啟用 Spanner API

gcloud services enable spanner.googleapis.com

摘要

在這個步驟中,您已設定專案 (如果尚未設定)、啟用 Cloud Shell,並啟用必要的 API。

下一步

接下來,您將設定 Spanner 執行個體和資料庫。

3. 建立 Spanner 執行個體和資料庫

建立 Spanner 執行個體

在這個步驟中,我們會為程式碼研究室設定 Spanner 執行個體。如要執行這項操作,請開啟 Cloud Shell 並執行下列指令:

export SPANNER_INSTANCE_ID=retail-demo
gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1

指令輸出:

$ gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
Creating instance...done.  

建立資料庫

執行個體啟動後,您就可以建立資料庫。Spanner 可在單一執行個體上建立多個資料庫。

資料庫是用於定義結構定義的所在位置。您也可以控制資料庫存取權、設定自訂加密、設定最佳化工具,以及設定保留期限。

如要建立資料庫,請再次使用 gcloud 指令列工具:

export SPANNER_DATABASE=cymbal-bikes
gcloud spanner databases create $SPANNER_DATABASE \
 --instance=$SPANNER_INSTANCE_ID

指令輸出:

$ gcloud spanner databases create $SPANNER_DATABASE \
 --instance=$SPANNER_INSTANCE_ID
Creating database...done.

摘要

在這個步驟中,您已建立 Spanner 執行個體和資料庫。

下一步

接下來,您將設定 Spanner 結構定義和資料。

4. 載入 Cymbal 結構定義和資料

建立 Cymbal 結構定義

如要設定結構定義,請前往 Spanner Studio:

3e1a0fed928b33cf.png

結構定義分為兩個部分。首先,您需要新增 products 資料表。複製並貼到空白分頁中。

在結構定義部分,請複製並貼入下列 DDL 至方塊中:

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);

接著,按一下 run 按鈕,等待幾秒鐘讓結構定義建立完成。

接下來,您將建立兩個模型,並將這些模型設為 Vertex AI 模型端點。

第一個模型是用於從文字產生嵌入資料的嵌入模型,第二個模型則是用於根據 Spanner 中的資料產生回覆的 LLM 模型。

將下列結構定義貼到 Spanner Studio 的新分頁中:

CREATE MODEL EmbeddingsModel INPUT(
content STRING(MAX),
) OUTPUT(
embeddings STRUCT<statistics STRUCT<truncated BOOL, token_count FLOAT32>, values ARRAY<FLOAT32>>,
) REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/<PROJECT_ID>/locations/us-central1/publishers/google/models/text-embedding-004'
);


CREATE MODEL LLMModel INPUT(
prompt STRING(MAX),
) OUTPUT(
content STRING(MAX),
) REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/<PROJECT_ID>/locations/us-central1/publishers/google/models/gemini-pro',
default_batch_size = 1
);

接著,按一下 run 按鈕,然後等待幾秒鐘,讓模型建立完成。

在 Spanner Studio 的左側窗格中,您應該會看到下列表格和模型:

62455aa4b0e839d9.png

載入資料

接下來,您需要將一些產品插入資料庫。在 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);

按一下 run 按鈕插入資料。

摘要

在這個步驟中,您已建立結構定義,並將一些基本資料載入 cymbal-bikes 資料庫。

下一步

接下來,您將整合嵌入模型,為產品說明產生嵌入資料,並將文字搜尋要求轉換為嵌入資料,以便搜尋相關產品。

5. 使用嵌入

為產品說明產生向量嵌入

如要讓相似搜尋功能適用於產品,你必須為產品說明產生嵌入。

在結構定義中建立 EmbeddingsModel 後,這就是簡單的 UPDATE DML 陳述式。

UPDATE products p1
SET productDescriptionEmbedding =
(SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel,
(SELECT productDescription as content FROM products p2 where p2.productId=p1.productId)))
WHERE categoryId=1;

按一下 run 按鈕更新產品說明。

在這個範例中,您會透過 SQL 查詢提供自然語言搜尋要求。這項查詢會將搜尋要求轉換為嵌入項目,然後根據先前步驟產生的產品說明所儲存的嵌入項目,搜尋類似的結果。

-- Use Spanner's vector search, and integration with embedding and LLM models to
-- return items that are semantically relevant and available in inventory based on
-- real-time data.


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;

按一下 run 按鈕,即可查看類似產品。結果應如下所示:

672e111753077fcf.png

請注意,查詢中使用了其他篩選器,例如只對有庫存的產品感興趣 (inventoryCount > 0)。

摘要

在這個步驟中,您使用 SQL 建立產品說明嵌入資料和搜尋要求嵌入資料,並利用 Spanner 與 Vertex AI 中模型的整合功能。您也執行向量搜尋,找出符合搜尋要求的類似產品。

後續步驟

接下來,我們將使用搜尋結果將資料輸入大型語言模型,為每項產品產生自訂回覆。

6. 使用大型語言模型

Spanner 可輕鬆整合 Vertex AI 提供的 LLM 模型。這可讓開發人員使用 SQL 直接與 LLM 介接,而不需要要求應用程式執行邏輯。

舉例來說,我們有來自使用者 "I'd like to buy a starter bike for my 3 year old child". 的先前 SQL 查詢結果

開發人員想針對每個結果,使用以下提示提供回覆,說明產品是否適合使用者:

"Answer with ‘Yes' or ‘No' and explain why: Is this a good fit for me? I'd like to buy a starter bike for my 3 year old child"

以下是可用的查詢:

-- Use an LLM to analyze this list and provide a recommendation on whether each
-- product is a good fit for the user. We use the vector search and real time
-- inventory data to first filter the products to reduce the size of the prompt to
-- the LLM.
SELECT productName, productDescription, inventoryCount, content AS LLMResponse
FROM ML.PREDICT(
MODEL LLMModel,
(   SELECT
inventoryCount,
productName,
productDescription,
CONCAT(
"Answer with ‘Yes' or ‘No' and explain why: Is this a good fit for me?",
"I'd like to buy a starter bike for my 3 year old child \n",
"Product Name: ", productName, "\n",
"Product Description:", productDescription) AS prompt,
FROM products
WHERE inventoryCount > 0
ORDER by 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)
)
)
) LIMIT 5
),
STRUCT(256 AS maxOutputTokens)
);

按一下 run 按鈕,即可發出查詢。結果應如下所示:

35878cd0f88f1470.png

第一項產品適合 3 歲兒童使用,因為產品說明中的年齡範圍是 2 到 4 歲。其他產品不太適合。

摘要

在這個步驟中,您使用大型語言模型,針對使用者提示產生基本回覆。

後續步驟

接下來,我們來瞭解如何使用 ANN 擴大向量搜尋。

7. 擴大向量搜尋

先前的向量搜尋範例採用了 KNN 向量搜尋。這項功能非常適合用於查詢特定的 Spanner 資料子集。這類查詢稱為高度可分割

如果您沒有高度可分區的工作負載,但有大量資料,建議您使用 ScaNN 演算法的 ANN 向量搜尋功能,提高查詢效能。

如要在 Spanner 中執行這項操作,您需要執行以下兩項操作:

  • 建立向量索引
  • 修改查詢,使用 APPROX 距離函式。

建立向量索引

如要在這個資料集上建立向量索引,我們必須先修改 productDescriptionEmbeddings 欄,定義每個向量的長度。如要將向量長度新增至資料欄,您必須先刪除原始資料欄,然後重新建立。

ALTER TABLE `products` DROP COLUMN `productDescriptionEmbedding`;
ALTER TABLE
  `products` ADD COLUMN `productDescriptionEmbedding` ARRAY<FLOAT32>(vector_length=>768);

接著,請再次透過先前執行的 Generate Vector embedding 步驟建立嵌入資料。

UPDATE products p1
SET productDescriptionEmbedding =
(SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel,
(SELECT productDescription as content FROM products p2 where p2.productId=p1.productId)))
WHERE categoryId=1;

建立資料欄後,請建立索引:

CREATE VECTOR INDEX ProductDescriptionEmbeddingIndex
    ON products(productDescriptionEmbedding)
    WHERE productDescriptionEmbedding IS NOT NULL
OPTIONS (
 distance_type = 'COSINE'
);

使用新索引

如要使用新的向量索引,您必須稍微修改先前的嵌入查詢。

以下是原始查詢:

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;

您必須進行下列變更:

  • 為新的向量索引使用索引提示:@{force_index=ProductDescriptionEmbeddingIndex}
  • COSINE_DISTANCE 函式呼叫變更為 APPROX_COSINE_DISTANCE請注意,下方最終查詢中的 JSON 選項也是必要的。
  • 分別從 ML.PREDICT 函式產生嵌入資料。
  • 將嵌入結果複製到最終查詢中。

產生嵌入

-- Generate the prompt embeddings
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)
  )
)

醒目顯示查詢結果,然後複製。

1b43c5ae4ef9ab68.png

接著,請貼上複製的嵌入資料,替換下列查詢中的 <VECTOR>

-- Embedding query now using the vector index


SELECT productName, productDescription, inventoryCount, 
  APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[@VECTOR], options => JSON '{\"num_leaves_to_search\": 10}')
FROM products @{force_index=ProductDescriptionEmbeddingIndex}
WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0
ORDER BY distance
LIMIT 5;

如下所示:

12397107ec49c491.png

摘要

在這個步驟中,您已將結構定義轉換為向量索引。然後,您重新撰寫嵌入查詢,以便使用向量索引執行 ANN 搜尋。隨著資料量增加,您需要擴大向量搜尋工作負載,這項步驟就非常重要。

後續步驟

接下來,該清理了!

8. 清除 (選用)

如要清理,請前往 Cloud 控制台的 Cloud Spanner 專區,刪除我們在程式碼研究室中建立的 'retail-demo' 執行個體。

41cbc1a84b3588d5.png

9. 恭喜!

恭喜!您已成功使用 Spanner 內建的向量搜尋功能執行相似度搜尋。此外,您也瞭解如何輕鬆使用嵌入和大型語言模型,直接透過 SQL 提供生成式 AI 功能。

最後,您瞭解了如何使用 ScaNN 演算法執行 ANN 搜尋,以便擴大向量搜尋工作負載。

後續步驟

如要進一步瞭解 Spanner 的 K 近鄰 (KNN 向量搜尋) 功能,請參閱以下網頁:https://cloud.google.com/spanner/docs/find-k-nearest-neighbors

如要進一步瞭解 Spanner 的近似最鄰近 (ANN 向量搜尋) 功能,請參閱以下網頁:https://cloud.google.com/spanner/docs/find-approximate-nearest-neighbors

您也可以參閱以下網頁,進一步瞭解如何使用 Spanner 的 Vertex AI 整合功能,透過 SQL 執行線上預測:https://cloud.google.com/spanner/docs/ml