本教學課程說明如何使用 Lakehouse 中的結構化銷售資料,分析非結構化自由文字格式的顧客意見回饋,評估新產品上市的成效。
假設您是 Froyo 的資料科學家。這間虛構的優格冰淇淋公司打算推出名為「午夜漩渦」的新口味。在決定全球發布前,商家需要回答三個問題:
- 新口味含有哪些過敏原?顧客有什麼意見回饋?
- 在接下來 12 個月內,該公司應預期現有口味的需求量為何?
- 顧客情緒和重複購買意願與預測需求相比如何?
本教學課程適用於熟悉 BigQuery 和基本 SQL 的資料分析師、資料科學家和資料工程師。您將使用 Cloud Shell 和 Google Cloud 控制台完成每個步驟。
目標
- 在 Lakehouse 執行階段目錄中建立目錄,然後建立 Apache Iceberg 資料表,將產品、銷售和顧客意見回饋資料儲存在 Lakehouse 中。
- 使用 BigQuery AI 函式
AI.CLASSIFY和AI.IF,從 Iceberg 資料表中儲存的非結構化文字擷取情緒、主題和購買意圖。 - 在 BigQuery Studio 中使用對話式數據分析,透過
AI.FORECAST預測 12 個月內的需求,並將預測結果與產品和意見回饋洞察資料合併。
費用
在本文件中,您將使用下列 Google Cloud計費元件:
- Lakehouse
- BigQuery, including conversational analytics
- Cloud Storage
- Gemini Enterprise Agent Platform, for the Gemini models that AI functions call
如要根據預測用量估算費用,請使用 Pricing Calculator。
完成本文所述工作後,您可以刪除建立的資源,避免繼續計費,詳情請參閱「清除所用資源」。
事前準備
在 Google Cloud 控制台的專案選擇器頁面中,選取或建立 Google Cloud 專案。
必要的角色
如要取得完成本教學課程中工作所需的權限,請要求管理員在專案中授予您下列 IAM 角色:
-
在 Lakehouse 執行階段目錄中建立及刪除目錄、命名空間和資料表:
BigLake 管理員 (
roles/biglake.admin) -
建立及刪除 Cloud Storage bucket,並授予目錄服務帳戶存取權:Storage 管理員 (
roles/storage.admin) -
透過 BigQuery 建立及修改資料表:
BigQuery 資料編輯器 (
roles/bigquery.dataEditor) -
在 BigQuery Studio 中執行查詢及使用對話式數據分析:
- BigQuery Studio 使用者 (
roles/bigquery.studioUser) - Gemini Data Analytics 無狀態對話使用者 (
roles/geminidataanalytics.dataAgentStatelessUser) - Gemini for Google Cloud 使用者 (
roles/cloudaicompanion.user)
- BigQuery Studio 使用者 (
-
透過 BigQuery AI 函式呼叫 Gemini 模型:
Agent Platform 使用者 (
roles/aiplatform.user)
如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。
準備環境
啟動 Cloud Shell、設定資源的環境變數, 並啟用必要的 API:
在 Google Cloud 控制台中啟用 Cloud Shell。如果系統提示您授權,請點選「授權」。
在 Cloud Shell 中,設定專案 ID、區域、bucket 名稱、目錄 ID 和命名空間的環境變數,以便在本教學課程中重複使用:
export PROJECT_ID=$(gcloud config get-value project) export REGION="us-central1" export BUCKET_NAME="${PROJECT_ID}-froyo-lakehouse" export CATALOG_ID="froyo_catalog" export NAMESPACE_ID="froyo_lakehouse"
為專案啟用必要的 API:
- BigQuery API (
bigquery.googleapis.com) - BigLake API (
biglake.googleapis.com),可存取 Lakehouse 執行階段目錄 - Cloud Storage API (
storage.googleapis.com) - Agent Platform API (
aiplatform.googleapis.com) - 對話式數據分析 API (
geminidataanalytics.googleapis.com) - Gemini for Google Cloud API (
cloudaicompanion.googleapis.com)
在 Cloud Shell 中啟用下列 API:
gcloud services enable \ bigquery.googleapis.com \ biglake.googleapis.com \ storage.googleapis.com \ aiplatform.googleapis.com \ geminidataanalytics.googleapis.com \ cloudaicompanion.googleapis.com \ --project=${PROJECT_ID}
- BigQuery API (
建立 Cloud Storage bucket
在 Cloud Shell 中,建立 Cloud Storage bucket 來儲存 Iceberg 資料表檔案:
gcloud storage buckets create gs://${BUCKET_NAME} \ --project=${PROJECT_ID} \ --location=${REGION}
在 Lakehouse 執行階段目錄中建立目錄
使用 Iceberg REST 目錄端點,以憑證販售模式建立目錄,讓目錄使用自動佈建的服務帳戶存取 bucket,您不必建立 BigQuery 連線:
在 Cloud Shell 中,以憑證販賣模式建立多個 bucket 的目錄:
gcloud biglake iceberg catalogs create ${CATALOG_ID} \ --project=${PROJECT_ID} \ --catalog-type=biglake \ --default-location=gs://${BUCKET_NAME} \ --primary-location=${REGION} \ --credential-mode=vended-credentials
將 bucket 的「Storage 物件使用者」(
roles/storage.objectUser) 角色,授予目錄的自動佈建服務帳戶:CATALOG_SA=$(gcloud biglake iceberg catalogs describe ${CATALOG_ID} \ --project=${PROJECT_ID} \ --format='value(biglake-service-account)') gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \ --member="serviceAccount:${CATALOG_SA}" \ --role="roles/storage.objectUser"
在目錄中為資料表建立命名空間:
gcloud biglake iceberg namespaces create ${NAMESPACE_ID} \ --project=${PROJECT_ID} \ --catalog=${CATALOG_ID}
建立 Iceberg 資料表
在目錄中建立三個 Iceberg 資料表,並載入範例資料:
products:儲存產品清單,包括新口味「午夜漩渦」和現有口味。sales_history:儲存現有口味的每月單位銷售量 (以 24 個月為限),並依區域劃分。customer_feedback:儲存意見回饋記錄。每列都會將結構化中繼資料 (feedback_id、submitted_date、flavor_name和channel) 與儲存非結構化自由文字的commentSTRING欄配對。
在 BigQuery 中,您可以使用四部分P.C.N.T. 命名結構 (Project.Catalog.Namespace.Table) 參照 Lakehouse 資料表。
在 Cloud Shell 中建立
products、sales_history和customer_feedback資料表,並填入範例資料。指令碼會依序執行每個陳述式,大約需要一分鐘才能完成:bq query --project_id=${PROJECT_ID} --location=${REGION} --use_legacy_sql=false << EOF -- Product list. CREATE TABLE \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.products\` ( product_name STRING, base_flavor STRING, status STRING, allergens STRING, target_regions STRING); INSERT INTO \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.products\` VALUES ('Midnight Swirl', 'Classic Chocolate', 'Planned launch', 'Milk, Soy', 'North America, Europe'), ('Classic Chocolate', 'Classic Chocolate', 'In market', 'Milk, Soy', 'North America, Europe, Asia Pacific'), ('Vanilla Bean', 'Vanilla Bean', 'In market', 'Milk', 'North America, Europe, Asia Pacific'), ('Strawberry Swirl', 'Strawberry Swirl', 'In market', 'Milk', 'North America, Europe, Asia Pacific'); -- Monthly sales history for the flavors that are in market. CREATE TABLE \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.sales_history\` ( sale_month DATE, flavor_name STRING, region STRING, units_sold INT64); INSERT INTO \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.sales_history\` WITH months AS ( SELECT sale_month FROM UNNEST(GENERATE_DATE_ARRAY( '2024-01-01', '2025-12-01', INTERVAL 1 MONTH)) AS sale_month ), flavors AS ( SELECT * FROM UNNEST([ STRUCT('Classic Chocolate' AS flavor_name, 1200 AS base_units), ('Vanilla Bean', 1000), ('Strawberry Swirl', 800)]) ), regions AS ( SELECT * FROM UNNEST([ STRUCT('North America' AS region, 1.0 AS region_factor), ('Europe', 0.8), ('Asia Pacific', 0.6)]) ) SELECT m.sale_month, f.flavor_name, r.region, CAST( f.base_units * r.region_factor -- Two percent month-over-month growth. * (1 + 0.02 * DATE_DIFF(m.sale_month, DATE '2024-01-01', MONTH)) -- Seasonal peak in July. * (1 + 0.25 * SIN(2 * ACOS(-1) * (EXTRACT(MONTH FROM m.sale_month) - 4) / 12)) AS INT64) AS units_sold FROM months AS m CROSS JOIN flavors AS f CROSS JOIN regions AS r; -- Customer feedback records with unstructured text in the comment column. CREATE TABLE \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.customer_feedback\` ( feedback_id INT64, submitted_date DATE, flavor_name STRING, channel STRING, comment STRING); INSERT INTO \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.customer_feedback\` VALUES (1, '2025-11-03', 'Midnight Swirl', 'Taste panel', "Rich, deep chocolate with a hint of salt. Honestly better than the classic chocolate. I'd order this every week."), (2, '2025-11-03', 'Midnight Swirl', 'Taste panel', "Loved the dark chocolate swirl, but it was a bit too bitter for my kids."), (3, '2025-11-04', 'Midnight Swirl', 'Taste panel', "Best froyo I've tried this year. Smooth texture and not too sweet."), (4, '2025-11-04', 'Midnight Swirl', 'Taste panel', "Great taste. I'd definitely buy it again if it's priced like the other flavors."), (5, '2025-11-05', 'Midnight Swirl', 'Taste panel', "Does this contain soy? I have a soy allergy so I skipped it. Please label it clearly."), (6, '2025-11-05', 'Midnight Swirl', 'Taste panel', "Tastes like a premium dessert. The sea salt really makes it."), (7, '2025-06-12', 'Classic Chocolate', 'App review', "Solid chocolate flavor, my go-to order."), (8, '2025-07-02', 'Classic Chocolate', 'App review', "It's fine, but a little too sweet compared to other brands."), (9, '2025-08-19', 'Classic Chocolate', 'Support email', "Consistently good. I wish the cups were bigger for the price."), (10, '2025-09-07', 'Classic Chocolate', 'Support email', "My chocolate froyo was icy this time and the texture was off."), (11, '2025-10-21', 'Classic Chocolate', 'App review', "Classic for a reason. Always creamy. I'll keep ordering it."), (12, '2025-11-05', 'Classic Chocolate', 'Taste panel', "Good but forgettable next to the new dark chocolate sample."), (13, '2025-05-14', 'Vanilla Bean', 'App review', "Real vanilla flavor, you can see the specks. Love it."), (14, '2025-06-30', 'Vanilla Bean', 'App review', "Pretty plain. I only order it as a base for toppings."), (15, '2025-08-02', 'Vanilla Bean', 'App review', "Creamy and simple, perfect for my toddler."), (16, '2025-09-15', 'Vanilla Bean', 'Support email', "The store was out of vanilla bean two weekends in a row."), (17, '2025-06-08', 'Strawberry Swirl', 'App review', "Tastes like fresh strawberries. Great in the summer."), (18, '2025-07-26', 'Strawberry Swirl', 'App review', "Too artificial tasting. Not a fan."), (19, '2025-08-11', 'Strawberry Swirl', 'Support email', "My favorite flavor. Please never discontinue it."), (20, '2025-10-03', 'Strawberry Swirl', 'App review', "The price went up, but it's still worth it."); EOF
確認目錄列出
products、sales_history和customer_feedback資料表:gcloud biglake iceberg tables list \ --project=${PROJECT_ID} \ --catalog=${CATALOG_ID} \ --namespace=${NAMESPACE_ID}
使用 AI 函式分析意見回饋
customer_feedback 資料表中的 comment 欄包含非結構化文字,無法直接匯總或聯結。使用 BigQuery AI 函式從每則留言中擷取結構化值,並建立新的feedback_insights資料表:
AI.CLASSIFY會根據您定義的類別清單,為每則留言指派情緒 (positive、neutral或negative) 和主要主題 (例如taste、texture、price或allergens)。AI.IF會評估每則留言的自然語言條件,並傳回BOOL值。在此情況下,值會指出顧客是否打算再次購買產品。
這些受管理 AI 函式會使用您的使用者憑證呼叫 Gemini,因此您不需要建立遠端模型或連線。
在 Cloud Shell 中,建立並填入
feedback_insights資料表:bq query --project_id=${PROJECT_ID} --location=${REGION} --use_legacy_sql=false << EOF CREATE TABLE \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.feedback_insights\` ( feedback_id INT64, flavor_name STRING, channel STRING, comment STRING, sentiment STRING, topic STRING, would_buy_again BOOL); INSERT INTO \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.feedback_insights\` SELECT feedback_id, flavor_name, channel, comment, AI.CLASSIFY( comment, categories => ['positive', 'neutral', 'negative']) AS sentiment, AI.CLASSIFY( comment, categories => ['taste', 'texture', 'price', 'allergens', 'availability', 'other']) AS topic, AI.IF( ('This customer says or implies that they would buy the product ', 'again. Comment: ', comment)) AS would_buy_again FROM \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.customer_feedback\`; EOF
總結各口味的意見回饋指標:
bq query --project_id=${PROJECT_ID} --location=${REGION} --use_legacy_sql=false << EOF SELECT flavor_name, COUNT(*) AS comments, COUNTIF(sentiment = 'positive') AS positive, COUNTIF(would_buy_again) AS would_buy_again, ROUND(COUNTIF(sentiment = 'positive') / COUNT(*), 2) AS positive_share FROM \`${PROJECT_ID}.${CATALOG_ID}.${NAMESPACE_ID}.feedback_insights\` GROUP BY flavor_name ORDER BY positive_share DESC; EOF
輸出結果會與下列內容相似:
+-------------------+----------+----------+-----------------+----------------+ | flavor_name | comments | positive | would_buy_again | positive_share | +-------------------+----------+----------+-----------------+----------------+ | Strawberry Swirl | 4 | 3 | 2 | 0.75 | | Midnight Swirl | 6 | 4 | 3 | 0.67 | | Vanilla Bean | 4 | 2 | 2 | 0.5 | | Classic Chocolate | 6 | 2 | 3 | 0.33 | +-------------------+----------+----------+-----------------+----------------+
透過對話式數據分析預測需求
您可以在 BigQuery Studio 中使用對話式數據分析,以自然語言分析 Iceberg 表格。這項功能會從 Lakehouse 執行階段目錄擷取資料表結構定義,生成並執行 BigQuery SQL (包括 AI.FORECAST 等 AI 函式),並直接在對話中傳回資料表和圖表。
與資料表展開對話
前往 Google Cloud 控制台的 BigQuery Agents 頁面。
在 BigQuery Studio 編輯器窗格中,按一下「代理」分頁標籤,開啟對話窗格,然後按一下「新對話」。
在「運用資料進行對話」窗格中,按一下「知識來源」分頁標籤。 在「搜尋來源」欄位中,使用下列值搜尋並選取三個 Iceberg 表格。將
PROJECT_ID替換為專案 ID:PROJECT_ID.froyo_catalog.froyo_lakehouse.productsPROJECT_ID.froyo_catalog.froyo_lakehouse.feedback_insightsPROJECT_ID.froyo_catalog.froyo_lakehouse.sales_history
按一下「Chat」。
提出問題,預測需求並評估發布成效
依序以自然語言提問,回答 Midnight Swirl 上市的三個業務問題:
在「Ask a question」(提問) 欄位中輸入下列提示,查看 Midnight Swirl 的產品詳細資料和顧客意見回饋,然後點按「傳送」圖示 send_spark:
Using products and feedback_insights, what are Midnight Swirl's allergens, base flavor, positive sentiment share, would_buy_again count, and customer concerns from negative or neutral comments?
代理程式會查詢這兩個表格,並回報 Midnight Swirl 是以 Classic Chocolate 為基礎,且含有牛奶和大豆。此外,報告也指出正面情緒占 0.67,六位消費者中有三位打算再次購買,並強調大豆過敏原標示和黑巧克力苦味的問題。
輸入下列提示,預測現有口味的 12 個月需求量,然後按一下「send_spark」send_spark「傳送」:
Forecast monthly sales by flavor for the next 12 months, plotting only the trend lines without confidence intervals.
對話式分析會使用
AI.FORECAST執行查詢,在 BigQuery ML 中使用內建的 TimesFM 模型,不必訓練個別模型,並顯示各口味的 12 個月預測圖表。輸入下列提示詞,將需求預測與顧客意見回饋合併,並取得發布建議,然後按一下「send_spark」send_spark「傳送」:
Join the total 12-month forecasted units_sold for each flavor with its positive sentiment share, would_buy_again count, and top complaint topics from feedback_insights, and recommend next steps for the Midnight Swirl launch.
選用:如要檢查生成的 SQL 查詢或查看代理的推論步驟,請展開「顯示思考過程」。
您可以在對話中提出後續問題 (例如按區域細分預測),或按一下「詳細資料」窗格中的「建立代理」,儲存並與團隊共用可重複使用的資料代理。
清除所用資源
如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。
刪除專案
- 前往 Google Cloud 控制台的「Manage resources」(管理資源) 頁面。
- 在專案清單中選取要刪除的專案,然後點選「Delete」(刪除)。
- 在對話方塊中輸入專案 ID,然後按一下 [Shut down] (關閉) 以刪除專案。
刪除個別資源
如要保留專案,請刪除您稍早建立的個別資源。
如要刪除對話,請在 BigQuery Studio 編輯器窗格中選取「代理」分頁標籤。在左側導覽面板 (可能需要展開) 中,找到「最近的對話」下方的對話,然後依序點選 more_vert「查看動作」> 刪除。
在 Cloud Shell 中,刪除四個資料表、命名空間、目錄和 Cloud Storage bucket:
for TABLE in products sales_history customer_feedback feedback_insights; do gcloud biglake iceberg tables delete ${TABLE} \ --project=${PROJECT_ID} \ --catalog=${CATALOG_ID} \ --namespace=${NAMESPACE_ID} \ --quiet done gcloud biglake iceberg namespaces delete ${NAMESPACE_ID} \ --project=${PROJECT_ID} \ --catalog=${CATALOG_ID} \ --quiet gcloud biglake iceberg catalogs delete ${CATALOG_ID} \ --project=${PROJECT_ID} \ --quiet gcloud storage rm -r gs://${BUCKET_NAME}
後續步驟
如要進一步瞭解如何處理 Lakehouse 資料,請參閱下列資源:
- 進一步瞭解如何使用 Lakehouse 中的對話式數據分析,以自然語言查詢 Iceberg 資料表。
- 在 BigQuery 中建立資料代理,即可設定自訂指令、已驗證的查詢和業務詞彙表。
- 使用資料洞察功能,為資料表生成說明和建議查詢。
- 瞭解如何管理 Lakehouse 執行階段目錄中的 Iceberg 資料表。