運用 Spanner AI 和 Graph 提供即時零售推薦

1. 簡介

本程式碼研究室將逐步說明如何使用 Spanner 的 AI 和圖形功能,強化現有的零售資料庫。您將學到實用技巧,瞭解如何在 Spanner 中運用機器學習技術,為顧客提供更優質的服務。具體來說,我們會導入 K 近鄰 (kNN) 和近似近鄰 (ANN) 演算法,發掘符合個別消費者需求的新產品。您也會整合 LLM,以清楚的自然語言說明推薦特定產品的原因。

除了建議之外,我們還會深入探討 Spanner 的圖表功能。您將使用圖形查詢,根據顧客的購買記錄和產品說明,建立產品之間的關係模型。這項做法可發掘深層相關的項目,大幅提升「購買此商品的顧客也買了」或「相關項目」功能的關聯性和效果。完成本程式碼研究室後,您將具備相關技能,完全透過 Google Cloud Spanner 建構智慧型、可擴充且回應迅速的零售應用程式。

情境

你任職於電子設備零售商。您的電子商務網站具有標準的 Spanner 資料庫,其中包含 ProductsOrdersOrderItems

顧客造訪你的網站,並有特定需求:「我想購買高效能鍵盤。我偶爾會在海灘上寫程式,所以可能會弄濕。」

您的目標是使用 Spanner 的進階功能,智慧地回應這項要求:

  1. 尋找:透過向量搜尋,尋找說明在語意上符合使用者要求的產品,而不只是簡單的關鍵字搜尋。
  2. 說明:使用 LLM 分析最符合條件的結果,並說明原因,建立顧客信任感。
  3. 關聯:使用圖表查詢,找出消費者經常與該推薦產品一起購買的其他產品。

2. 事前準備

  1. 建立專案:在 Google Cloud 控制台的專案選取器頁面中,選取或建立 Google Cloud 專案。
  2. 啟用帳單:確認 Cloud 專案已啟用帳單。瞭解如何檢查專案是否已啟用計費功能
  3. 啟用 Cloud Shell:按一下控制台中的「啟用 Cloud Shell」按鈕,即可啟用 Cloud Shell。您可以在 Cloud Shell 終端機和編輯器之間切換。

c3c8bfefc88138cc.png

  1. 授權及設定專案:連線至 Cloud Shell 後,請確認您已通過驗證,且專案已設為您的專案 ID。
gcloud auth list
gcloud config list project
  1. 如果未設定專案,請使用下列指令設定,並將 <PROJECT_ID> 替換為實際的專案 ID:
export PROJECT_ID=<PROJECT_ID>
gcloud config set project $PROJECT_ID
  1. 啟用必要 API:啟用 Spanner、Vertex AI 和 Compute Engine API。這可能需要幾分鐘的時間。
gcloud services enable \
    spanner.googleapis.com \
    aiplatform.googleapis.com \
    compute.googleapis.com
  1. 設定幾個會重複使用的環境變數。
export INSTANCE_ID=my-first-spanner
export INSTANCE_CONFIG=regional-us-central1
  1. 如果您還沒有 Spanner 執行個體,請建立免費試用 Spanner 執行個體。您需要 Spanner 執行個體來代管資料庫。我們將使用 regional-us-central1 做為設定。如要更新,請前往該頁面。
gcloud spanner instances create $INSTANCE_ID \
   --instance-type=free-instance --config=$INSTANCE_CONFIG \
   --description="Trial Instance" 

3. 架構總覽

Spanner 會封裝所有必要功能,但模型除外,因為模型是託管在 Vertex AI 上。

4. 步驟 1:設定資料庫並提交第一項查詢。

首先,我們需要建立資料庫、載入零售業範例資料,並告知 Spanner 如何與 Vertex AI 通訊。

這個部分會用到下列 SQL 指令碼。

  1. 前往 Spanner 的產品頁面。
  2. 選取正確的執行個體。

a8792346efb017d5.png

  1. 在畫面上選取「探索資料集」。然後在彈出式視窗中選取「零售」選項。

49800ad520771ecb.png

c2a7cd37d5c1c493.png

  1. 前往 Spanner Studio。 Spanner Studio 包含「Explorer」窗格,可與查詢編輯器和 SQL 查詢結果表整合。您可以在這個介面中執行 DDL、DML 和 SQL 陳述式。你必須展開側邊選單,然後尋找放大鏡圖示。

b6a188814a821aba.png

  1. 閱讀產品表格。建立新分頁,或使用已建立的「未命名的查詢」分頁。

cb65b9aa4e7138b1.png

SELECT *
FROM Products;

5. 步驟 2:建立 AI 模型。

現在,我們來使用 Spanner 物件建立遠端模型。這些 SQL 陳述式會建立連結至 Vertex AI 端點的 Spanner 物件。

  1. 在 Spanner Studio 中開啟新分頁,然後建立兩個模型。第一個是 EmbeddingsModel,可讓您生成嵌入。第二個是 LLMModel,可讓您與 LLM 互動 (在本範例中為 gemini-2.5-flash)。請確認您已將 <PROJECT_ID> 更新為專案 ID。
### Create the Embedding Model object in Spanner
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-005'
);

### Create the LLM Model object in Spanner
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-2.5-flash',
default_batch_size = 1
);
  1. 注意:請記得將 PROJECT_ID 替換為實際的 $PROJECT_ID

67f60ff3a90e926c.png

測試這個步驟:您可以在 SQL 編輯器中執行下列指令,確認模型是否已建立。

SELECT *
FROM information_schema.models;

9d2c9cab3733a964.png

6. 步驟 3:產生及儲存向量嵌入

我們的產品資料表含有文字說明,但 AI 模型會解讀向量 (數字陣列)。我們需要新增資料欄來儲存這些向量,然後透過 EmbeddingsModel 執行所有產品說明,將向量填入資料欄。

  1. 建立新資料表來支援嵌入項目。首先,請建立可支援嵌入項目的資料表。我們使用的嵌入模型與產品表格範例嵌入不同。您必須確保向量搜尋功能正常運作,且嵌入是從同一個模型生成。
CREATE TABLE products_with_embeddings (
   ProductID INT64,
   embedding_vector ARRAY<FLOAT32>(vector_length=>768),
   embedding_text STRING(MAX)
)
PRIMARY KEY (ProductID);
  1. 在新的資料表中填入模型生成的嵌入項目。為求簡單,我們在這裡使用 insert into 陳述式。這會將查詢結果推送到您剛才建立的資料表。

SQL 陳述式會先擷取並串連所有要產生嵌入的相關文字資料欄。然後傳回相關資訊,包括我們使用的文字。一般來說,這並非必要步驟,但我們仍會加入,方便您查看結果。

INSERT INTO products_with_embeddings (productId, embedding_text, embedding_vector)
SELECT
ProductID,
content as embedding_text,
embeddings.values as embedding_vector
FROM ML.PREDICT(
 MODEL EmbeddingsModel,
 (
   SELECT
   ProductID,
   embedding_text AS content
   FROM (
     SELECT
       ProductID,
       CONCAT(
         Category,
         " ",
         Description,
         " ",
         Name
       ) AS embedding_text
       FROM products)));
  1. 檢查新的嵌入內容。現在您應該會看到產生的嵌入。
SELECT *
FROM products_with_embeddings
LIMIT 1;

d40975087736e604.png

7. 步驟 4:建立 ANN 搜尋的向量索引

如要立即搜尋數百萬個向量,我們需要索引。這個索引可啟用Approximate Nearest Neighbor (ANN) 搜尋,速度極快且可水平擴充。

  1. 執行下列 DDL 查詢來建立索引。我們將 COSINE 指定為距離指標,這非常適合語意文字搜尋。請注意,WHERE 子句實際上是必要的,因為 Spanner 會將其設為查詢的必要條件。
CREATE VECTOR INDEX DescriptionEmbeddingIndex
   ON products_with_embeddings(embedding_vector)
   WHERE embedding_vector IS NOT NULL
OPTIONS (
 distance_type = 'COSINE'
);
  1. 在「作業」分頁中查看索引建立狀態。

2ad9c88bc86b77f0.png

8. 步驟 5:使用 K 近鄰 (KNN) 搜尋功能尋找建議

現在來到有趣的部分!讓我們找出符合顧客查詢的產品:「我想購買高效能鍵盤。我有時會在海灘上寫程式,所以可能會弄濕。」

首先介紹 K 最近鄰 (KNN) 搜尋。這是精確搜尋,會將查詢向量與每個產品向量進行比較。雖然精確度高,但處理大型資料集時可能會比較慢 (這也是我們在步驟 5 中建立 ANN 索引的原因)。

這項查詢會執行以下兩項作業:

  1. 子查詢會使用 ML.PREDICT 取得顧客查詢的嵌入向量。
  2. 外部查詢會使用 COSINE_DISTANCE 計算查詢向量與每個產品的 embedding_vector 之間的「距離」。距離越小,表示越相符。
SELECT
    productid,
    embedding_text,
    COSINE_DISTANCE(
      embedding_vector,
      (
        SELECT embeddings.values
        FROM ML.PREDICT(
          MODEL EmbeddingsModel,
          (SELECT "I'd like to buy a high performance keyboard. I sometimes code while I'm at the beach so it may get wet." AS content)
        )
      )
    ) AS distance
FROM products_with_embeddings
WHERE embedding_vector IS NOT NULL
ORDER BY distance
LIMIT 5;

畫面上會顯示產品清單,防水鍵盤會列在最上方。

9. 步驟 6:使用近似 (ANN) 搜尋功能尋找建議

KNN 很棒,但對於每秒有數百萬項產品和數千項查詢的正式系統,我們需要 ANN 索引的速度。

使用索引時,您必須指定 APPROX_COSINE_DISTANCE 函式。

  1. 如上所述,取得文字的向量嵌入。我們將該結果與 products_with_embeddings 資料表中的記錄進行交叉聯結,方便您在 APPROX_COSINE_DISTANCE 函式中使用。
WITH vector_query as
(
 SELECT embeddings.values as vector
 FROM ML.PREDICT(
 MODEL EmbeddingsModel,
  (SELECT "I'd like to buy a high performance keyboard. I sometimes code while I'm at the beach so it may get wet." as content)
 )
)
SELECT
ProductID,
embedding_text,
APPROX_COSINE_DISTANCE(embedding_vector, vector, options => JSON '{\"num_leaves_to_search\": 10}') distance
FROM products_with_embeddings @{force_index=DescriptionEmbeddingIndex},
vector_query
WHERE embedding_vector IS NOT NULL
ORDER BY distance
LIMIT 5;

預期輸出內容:結果應與 KNN 查詢相同或非常相似,但使用索引後,執行效率會大幅提升。您可能不會在範例中注意到這一點。

10. 步驟 7:使用 LLM 說明建議事項

只顯示產品清單是不錯的做法,但說明產品是否合適的原因更好。我們可以透過 LLMModel (Gemini) 執行這項操作。

這項查詢會將步驟 4 中的 KNN 查詢,巢狀內嵌至 ML.PREDICT 呼叫中。我們使用 CONCAT 為 LLM 建構提示,提供下列資訊:

  1. 明確的指示 (例如「請回答『是』或『否』,並說明原因...」)。
  2. 顧客的原始查詢。
  3. 每個最相符產品的名稱和說明。

接著,LLM 會根據查詢評估每項產品,並以自然語言提供回覆。

SELECT
   ProductID,
   embedding_text,
   content AS LLMResponse
FROM ML.PREDICT(
   MODEL LLMModel,
   (
     SELECT
       ProductID,
       embedding_text,
       CONCAT(
         "Answer with ‘Yes' or ‘No' and explain why: Is this a good fit for me?",
         "I'd like to buy a high performance keyboard. I sometimes code while I'm at the beach so it may get wet. \n",
         "Product Description:", embedding_text
       ) AS prompt,
     FROM products_with_embeddings
     WHERE embedding_vector IS NOT NULL
     ORDER BY COSINE_DISTANCE(
       embedding_vector,
       (
         SELECT embeddings.values
         FROM ML.PREDICT(
           MODEL EmbeddingsModel,
           (SELECT "I'd like to buy a high performance keyboard. I sometimes code while I'm at the beach so it may get wet." AS content)
         )
       )
     )
     LIMIT 5
   ),
   STRUCT(1056 AS maxOutputTokens)
);

預期輸出:您會取得含有新 LLMResponse 資料欄的表格。回覆內容應如下所示:「不會。原因如下:* 『防潑水』並非『防水』。「抗水」鍵盤可承受潑濺、小雨或打翻飲料

11. 步驟 8:建立屬性圖

現在來看看另一種建議:「購買這項產品的顧客也買了...」

這是以關係為基礎的查詢。屬性圖是這項作業的絕佳工具。Spanner 可讓您在現有資料表上建立圖表,不必複製資料。

這個 DDL 陳述式會定義圖表:

  • 節點: ProductUser 資料表。節點是您想從中衍生關係的實體,您想瞭解購買您產品的顧客是否也購買了「XYZ」產品。
  • 邊緣:Orders 表格,將 User (來源) 連結至 Product (目的地),並加上「已購買」標籤。邊緣則提供使用者與所購商品之間的關係。
CREATE PROPERTY GRAPH RetailGraph
 NODE TABLES (
   products_with_embeddings,
   Orders
 )
 EDGE TABLES (
   OrderItems
     SOURCE KEY (OrderID) REFERENCES Orders
     DESTINATION KEY (ProductID) REFERENCES products_with_embeddings
     LABEL Purchased
 );

12. 步驟 9:結合 Vector Search 和圖形查詢

這是最重要的一步。我們會在單一陳述式中結合 AI 向量搜尋和圖形查詢,找出相關產品。

這項查詢分為三部分,並以 NEXT statement 分隔,讓我們將其細分為幾個區段。

  1. 首先,我們會使用向量搜尋找出最相符的結果。
  2. ML.PREDICT 會使用 EmbeddingsModel,從使用者的文字查詢生成向量嵌入。
  3. 這項查詢會計算所有產品的新嵌入向量與儲存的 p.embedding_vector 之間的 COSINE_DISTANCE。
  4. 系統會選取並傳回距離最短 (語意相似度最高) 的單一最佳比對產品。
  5. 接著,我們會在圖表中搜尋關係。

NEXT MATCH (bestMatch)<-[:Purchased]-(user:Orders)-[:Purchased]->(purchasedWith:products_with_embeddings)

  1. 查詢會從 bestMatch 回溯至常見的 Orders 節點 (使用者),然後轉送至其他 purchasedWith 產品。
  2. 這項查詢會篩除原始產品,並使用 GROUP BY 和 COUNT(1) 彙整項目共同購買的頻率。
  3. 系統會傳回前 3 項共同購買的產品 (purchasedWith),並依共同出現的頻率排序。

此外,我們還會找出使用者訂單關係。

NEXT MATCH (bestMatch)<-[:Purchased]-(user:Orders)-[purchased:Purchased]->(purchasedWith)

  1. 這個中繼步驟會執行遍歷模式,以繫結主要實體:bestMatch、連結的使用者:Orders 節點,以及 purchasedWith 項目。
  2. 具體來說,這會將關係本身繫結為已購買,以便在下一個步驟中擷取資料。
  3. 這個模式可確保建立環境,以便擷取訂單和產品的詳細資料。
  4. 最後,我們輸出要傳回的結果,因為圖形節點必須先經過格式化,才能以 SQL 結果的形式傳回。
GRAPH RetailGraph
MATCH (p:products_with_embeddings)
WHERE p.embedding_vector IS NOT NULL
RETURN p AS bestMatch
ORDER BY COSINE_DISTANCE(
 p.embedding_vector,
 (
   SELECT embeddings.values
   FROM ML.PREDICT(
     MODEL EmbeddingsModel,
     (SELECT "I'd like to buy a high performance keyboard. I sometimes code while I'm at the beach so it may get wet." AS content)
   )
 )
)
LIMIT 1

NEXT
MATCH (bestMatch)<-[:Purchased]-(user:Orders)-[:Purchased]->(purchasedWith:products_with_embeddings)
FILTER bestMatch.productId <> purchasedWith.productId
RETURN bestMatch, purchasedWith
GROUP BY bestMatch, purchasedWith
ORDER BY COUNT(1) DESC
LIMIT 3

NEXT
MATCH (bestMatch)<-[:Purchased]-(user:Orders)-[purchased:Purchased]->(purchasedWith)
RETURN
 TO_JSON(Purchased) AS purchased,
 TO_JSON(user.OrderID) AS user,
 TO_JSON(purchasedWith.productId) AS purchasedWith;

預期輸出內容:您會看到代表前 3 項共同購買商品的 JSON 物件,提供交叉銷售建議。

13. 清除

為避免產生費用,您可以刪除建立的資源。

  1. 刪除 Spanner 執行個體:刪除執行個體時,資料庫也會一併刪除。
gcloud spanner instances delete my-first-spanner --quiet
  1. 刪除 Google Cloud 專案:如果您是專為本程式碼研究室建立專案,刪除專案就是最簡單的清理方式。
  • 前往 Google Cloud 控制台的「管理資源」頁面。
  • 選取專案並按一下「刪除」

🎉 恭喜!

您已成功使用 Spanner AI 和 Graph 建構精密的即時推薦系統!

您已瞭解如何將 Spanner 與 Vertex AI 整合,用於嵌入和 LLM 生成作業;如何執行高速向量搜尋 (KNN 和 ANN),找出語意相關的產品;以及如何使用圖形查詢來發掘產品關係。您已建構的系統不僅能尋找產品,還能說明推薦內容和建議相關項目,而且全都在單一可擴充的資料庫中完成。