このチュートリアルでは、Lakehouse で構造化された販売データを使用して、構造化されていない自由形式の顧客フィードバックを分析し、新製品のリリースを評価する方法について説明します。
架空のフローズン ヨーグルト会社である Froyo のデータ サイエンティストとして、Midnight Swirl という新しいフレーバーをリリースする計画があるとします。グローバル リリースを決定する前に、ビジネスは次の 3 つの質問に答える必要があります。
- 新しいフレーバーに適用されるアレルゲンとお客様のフィードバックの懸念事項は何ですか?
- 今後 12 か月間で、既存のフレーバーの需要はどの程度になると予想されますか?
- 顧客の感情とリピート購入の意向は、予測された需要とどのように比較されますか?
このチュートリアルは、BigQuery と基本的な SQL に精通しているデータ アナリスト、データ サイエンティスト、データ エンジニアを対象としています。すべての手順は、Cloud Shell と Google Cloud コンソールを使用して完了します。
目標
- Lakehouse ランタイム カタログにカタログを作成し、Lakehouse に商品、販売、顧客フィードバックのデータを保存する Apache Iceberg テーブルを作成します。
- 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
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
Google Cloud コンソールのプロジェクト セレクタ ページで、 Google Cloud プロジェクトを選択または作成します。
Google Cloud プロジェクトで課金が有効になっていることを確認します。
必要なロール
このチュートリアルのタスクを完了するために必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。
-
Lakehouse ランタイム カタログでカタログ、名前空間、テーブルを作成および削除する: BigLake 管理者 (
roles/biglake.admin) -
Cloud Storage バケットを作成して削除し、カタログ サービス アカウントにアクセス権を付与する: ストレージ管理者 (
roles/storage.admin) -
BigQuery からテーブルを作成して変更する: BigQuery データ編集者 (
roles/bigquery.dataEditor) -
BigQuery Studio でクエリを実行し、会話型分析を使用する:
- BigQuery Studio ユーザー (
roles/bigquery.studioUser) - Gemini データ分析ステートレス チャット ユーザー (
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、リージョン、バケット名、カタログ 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) - Lakehouse ランタイム カタログへのアクセスを提供する BigLake API(
biglake.googleapis.com) - Cloud Storage API(
storage.googleapis.com) - Agent Platform API(
aiplatform.googleapis.com) - Conversational Analytics 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 バケットを作成する
Cloud Shell で、Iceberg テーブル ファイルを保存する Cloud Storage バケットを作成します。
gcloud storage buckets create gs://${BUCKET_NAME} \ --project=${PROJECT_ID} \ --location=${REGION}
Lakehouse ランタイム カタログにカタログを作成する
Iceberg REST カタログ エンドポイントを使用して、カタログが自動プロビジョニングされたサービス アカウントを使用してバケットにアクセスし、BigQuery 接続を作成する必要がないように、認証情報ベンディング モードでカタログを作成します。
Cloud Shell で、認証情報ベンディング モードでマルチバケット カタログを作成します。
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
カタログの自動プロビジョニングされたサービス アカウントに、バケットに対する 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"
カタログにテーブルの Namespace を作成します。
gcloud biglake iceberg namespaces create ${NAMESPACE_ID} \ --project=${PROJECT_ID} \ --catalog=${CATALOG_ID}
Iceberg テーブルを作成する
カタログに 3 つの Iceberg テーブルを作成し、サンプルデータを読み込みます。
products: 新しい Midnight Swirl フレーバーと、そのベースとなる既存のフレーバーを含む商品リストを保存します。sales_history: 既存のフレーバーの月単位の販売数をリージョン別に 24 か月分保存します。customer_feedback: フィードバック レコードを保存します。各行は、構造化メタデータ(feedback_id、submitted_date、flavor_name、channel)と、非構造化自由テキストを格納するcommentSTRING列をペアにします。
BigQuery では、4 部構成の P.C.N.T. 命名構造(Project.Catalog.Namespace.Table)を使用して Lakehouse テーブルを参照します。
Cloud Shell で、
products、sales_history、customer_feedbackの各テーブルを作成し、サンプルデータを入力します。スクリプトは各ステートメントを順番に実行し、完了までに約 1 分かかります。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 の [エージェント] ページに移動します。
BigQuery Studio エディタ ペインで、[エージェント] タブをクリックして会話ペインを開き、[新しいチャット] をクリックします。
[データとチャットする] ペインで、[ナレッジ ソース] タブをクリックします。[ソースを検索] フィールドで、次の値を使用して 3 つの 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
[チャット] をクリックします。
質問して需要を予測し、リリースを評価する
一連の自然言語の質問をして、Midnight Swirl のリリースに関する次の 3 つのビジネス上の質問に回答します。
[質問する] フィールドに、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 で、6 人中 3 人が再購入を希望していることも報告されています。一方で、大豆アレルゲンのラベル表示とダーク チョコレートの苦味に関する懸念も指摘されています。
次のプロンプトを入力して、既存のフレーバーの 12 か月間の需要を予測し、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] [送信] をクリックします。
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 コンソールで [リソースの管理] ページに移動します。
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。
リソースを個別に削除する
プロジェクトを残しておく場合は、作成したリソースを個別に削除します。
会話を削除するには、BigQuery Studio エディタ ペインで [エージェント] タブを選択します。左側のナビゲーション パネル(展開が必要な場合があります)で、[最近のチャット] の下にある会話を見つけて、more_vert [アクションを表示> 削除] をクリックします。
Cloud Shell で、4 つのテーブル、Namespace、カタログ、Cloud Storage バケットを削除します。
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 テーブルを管理する方法を学習する。