開始使用 Spanner Vector Search

1. 簡介

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

Spanner 內建向量搜尋支援功能,可讓您執行相似度或語意搜尋,並在生成式 AI 應用程式中大規模實作檢索增強生成 (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 應用程式),請先建立帳戶。登入 Google Cloud Platform 主控台 ( console.cloud.google.com),然後建立新專案。

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

6c9406d9b014760.png

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

949d83c8a4ee17d9.png

如果您還沒有專案,應該會看到如下對話方塊,請建立第一個專案:

870a3cbd6541ee86.png

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

6a92c57d3250a4b3.png

請記住專案 ID,所有 Google Cloud 專案的專案 ID 都是不重複的名稱 (上述名稱已遭占用,因此不適用於您,抱歉!)。本程式碼研究室稍後會將其稱為 PROJECT_ID。

接下來,如果尚未啟用,請在開發人員控制台中啟用帳單,以便使用 Google Cloud 資源,並啟用 Spanner API

15d0ef27a8fbab27.png

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

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

設定 Google Cloud Shell

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

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

  1. 如要從 Cloud Shell 啟動 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
--edition=ENTERPRISE

指令輸出:

$ gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
--edition=ENTERPRISE
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 模型端點。

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

將下列結構定義貼到 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 資料庫。

下一步

接著,您會與 Embedding 模型整合,為產品說明生成嵌入項目,並將文字搜尋要求轉換為嵌入項目,以搜尋相關產品。

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 中模型的整合功能。您也執行了向量搜尋,找出符合搜尋要求的相似產品。

後續步驟

接著,我們將使用搜尋結果,讓 LLM 為每項產品生成自訂回覆。

6. 使用 LLM

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

第一個產品的產品說明中指出適合 2 到 4 歲的兒童,因此適合 3 歲兒童。其他產品不太適合。

摘要

在本步驟中,您使用 LLM 生成使用者提示的基本回覆。

後續步驟

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

7. 擴充向量搜尋功能

先前的向量搜尋範例採用的是精確的 KNN 向量搜尋。如果您可以查詢 Spanner 資料的特定子集,這項功能就非常實用。這類查詢稱為「高度可分割」。

如果工作負載無法高度分割,且資料量龐大,建議使用 ANN 向量搜尋,並採用 ScaNN 演算法,提升查閱效能。

如要在 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 Console 的「Cloud Spanner」部分,然後刪除我們在程式碼研究室中建立的「'retail-demo'」執行個體。

41cbc1a84b3588d5.png

9. 恭喜!

恭喜!您已成功使用 Spanner 內建的向量搜尋功能執行相似度搜尋。此外,您也瞭解到使用嵌入和 LLM 模型有多麼簡單,可以直接透過 SQL 提供生成式 AI 功能。

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

後續步驟

如要進一步瞭解 Spanner 的精確近鄰 (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