חיזוי הביקוש על סמך משוב מלקוחות באמצעות Lakehouse ו-AI

במדריך הזה נסביר איך לנתח משוב מלקוחות בטקסט חופשי לא מובנה עם נתוני מכירות מובנים ב-Lakehouse כדי להעריך השקת מוצר חדש.

נניח שאתם מדעני נתונים בחברת Froyo, חברה פיקטיבית לייצור יוגורט קפוא, שמתכננת להשיק טעם חדש בשם Midnight Swirl. לפני שמתחייבים להשקה גלובלית, העסק צריך לענות על שלוש שאלות:

  • אילו אלרגנים ובעיות שקשורות למשוב לקוחות רלוונטיים לטעם החדש?
  • מהו הביקוש שהחברה צריכה לצפות לו לטעמים הקיימים ב-12 החודשים הבאים?
  • מה ההבדל בין סנטימנט הלקוחות והכוונה שלהם לרכוש שוב לבין הביקוש הצפוי?

המדריך הזה מיועד למנתחי נתונים, למדעני נתונים ולמהנדסי נתונים שמכירים את BigQuery ואת SQL בסיסי. אתם משלימים כל שלב באמצעות Cloud Shell ומסוף Google Cloud .

מטרות

  • יוצרים קטלוג בקטלוג זמן הריצה של Lakehouse, ואז יוצרים טבלאות Apache Iceberg שמאחסנות נתונים של מוצרים, מכירות ומשוב לקוחות ב-Lakehouse.
  • משתמשים בפונקציות ה-AI של BigQuery‏ AI.CLASSIFY ו-AI.IF כדי לחלץ סנטימנט, נושאים וכוונת רכישה מטקסט לא מובנה שמאוחסן בטבלת Iceberg.
  • שימוש בניתוח נתוני שיחות ב-BigQuery Studio כדי לחזות את הביקוש ל-12 חודשים באמצעות AI.FORECAST, ושילוב התחזית עם תובנות לגבי מוצרים ומשוב.

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

כדי ליצור הערכת עלויות בהתאם לשימוש החזוי, אתם יכולים להשתמש במחשבון התמחור.

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

כשמסיימים את המשימות שמתוארות במסמך הזה אפשר למחוק את המשאבים שיצרתם כדי להימנע מחיובים נוספים. מידע נוסף זמין בקטע הסרת המשאבים.

לפני שמתחילים

  1. בדף לבחירת הפרויקט במסוף Google Cloud , בוחרים פרויקט ב- Google Cloud או יוצרים אותו.

    כניסה לדף לבחירת הפרויקט

  2. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות לביצוע המשימות במדריך הזה, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

יכול להיות שאפשר לקבל את ההרשאות הנדרשות גם באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש.

הכנת הסביבה

מפעילים את Cloud Shell, מגדירים משתני סביבה למשאבים ומפעילים את ממשקי ה-API הנדרשים:

  1. במסוף Google Cloud , מפעילים את Cloud Shell. אם מוצגת בקשה, לוחצים על Authorize (אישור).

    הפעלת Cloud Shell

  2. ב-Cloud Shell, מגדירים משתני סביבה למזהה הפרויקט, לאזור, לשם הקטגוריה, למזהה הקטלוג ולמרחב השמות, כדי שאפשר יהיה להשתמש בהם שוב במהלך המדריך הזה:

    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"
  3. מפעילים את ממשקי ה-API הנדרשים בפרויקט:

    • ‫BigQuery API‏ (bigquery.googleapis.com)
    • ‫BigLake API ‏ (biglake.googleapis.com), שמאפשר גישה לקטלוג של Lakehouse בזמן ריצה
    • 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)

    מפעילים את ממשקי ה-API האלה ב-Cloud Shell:

    gcloud services enable \
        bigquery.googleapis.com \
        biglake.googleapis.com \
        storage.googleapis.com \
        aiplatform.googleapis.com \
        geminidataanalytics.googleapis.com \
        cloudaicompanion.googleapis.com \
        --project=${PROJECT_ID}

יצירת קטגוריה של Cloud Storage

ב-Cloud Shell, יוצרים קטגוריה של Cloud Storage לאחסון קבצי טבלאות Iceberg:

gcloud storage buckets create gs://${BUCKET_NAME} \
    --project=${PROJECT_ID} \
    --location=${REGION}

יצירת קטלוג בקטלוג ייעודי לזמן ריצה של Lakehouse

באמצעות נקודת הקצה של קטלוג REST של Iceberg, יוצרים קטלוג במצב של הקצאת פרטי כניסה, כך שהקטלוג משתמש בחשבון השירות שהוקצה לו אוטומטית כדי לגשת לקטגוריה, ולא צריך ליצור חיבור ל-BigQuery:

  1. ב-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
  2. מקצים לחשבון השירות שהוקצה אוטומטית לקטלוג את התפקיד 'משתמש באובייקט אחסון' (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"
  3. יוצרים מרחב שמות לטבלאות בקטלוג:

    gcloud biglake iceberg namespaces create ${NAMESPACE_ID} \
        --project=${PROJECT_ID} \
        --catalog=${CATALOG_ID}

יצירת טבלאות Iceberg

יוצרים שלושה טבלאות Iceberg בקטלוג וטוענים אותן עם נתונים לדוגמה:

  • ‫products: מאחסן את רשימת המוצרים, כולל הטעם החדש Midnight Swirl והטעם הקיים שהוא מבוסס עליו.
  • ‫sales_history: מאחסן נתוני מכירות של יחידות חודשיות במשך 24 חודשים עבור הטעמים הקיימים, לפי אזור.
  • ‫customer_feedback: אחסון רשומות של משוב. כל שורה משלבת מטא-נתונים מובנים (feedback_id,‏ submitted_date,‏ flavor_name ו-channel) עם עמודה comment STRING שבה מאוחסן טקסט חופשי לא מובנה.

ב-BigQuery, כשמפנים לטבלאות Lakehouse משתמשים במבנה שמות בן ארבעה חלקים (Project.Catalog.Namespace.Table).

  1. ב-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
  2. מוודאים שבקטלוג מופיעות הטבלאות products, sales_history ו-customer_feedback:

    gcloud biglake iceberg tables list \
        --project=${PROJECT_ID} \
        --catalog=${CATALOG_ID} \
        --namespace=${NAMESPACE_ID}

ניתוח משוב באמצעות פונקציות AI

העמודה comment בטבלה customer_feedback מכילה טקסט לא מובנה שלא ניתן לצבור או לאחד ישירות. משתמשים בפונקציות AI של BigQuery כדי לחלץ ערכים מובְנים מכל תגובה וליצור טבלת feedback_insights חדשה:

  • ‫AI.CLASSIFY מקצה לכל תגובה סנטימנט (positive, ‏neutral או negative) ונושא ראשי (כמו taste, ‏texture, ‏price או allergens) מתוך רשימות של קטגוריות שאתם מגדירים.
  • ‫AI.IF מעריכה תנאי בשפה טבעית לכל תגובה ומחזירה ערך BOOL. במקרה כזה, הערך מציין אם הלקוח מתכוון לקנות את המוצר שוב.

הפונקציות המנוהלות של AI משתמשות בפרטי הכניסה של המשתמש כדי להתקשר אל Gemini, כך שלא צריך ליצור מודל מרוחק או חיבור.

  1. ב-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
  2. סכם את מדדי המשוב לכל טעם:

    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 כמו AI.FORECAST), ומחזיר טבלאות ותרשימים ישירות בצ'אט.

איך מתחילים שיחה לגבי טבלאות

  1. במסוף Google Cloud , עוברים לדף Agents ב-BigQuery.

    כניסה לדף Agents

  2. בחלונית העריכה של BigQuery Studio, לוחצים על הכרטיסייה סוכנים כדי לפתוח את חלונית השיחה, ואז לוחצים על שיחה חדשה.

  3. בחלונית צ'אט עם הנתונים שלך, לוחצים על הכרטיסייה מקורות מידע. בשדה חיפוש מקורות, מחפשים ובוחרים את שלושת טבלאות Iceberg באמצעות הערכים הבאים. מחליפים את PROJECT_ID במזהה הפרויקט:

    • PROJECT_ID.froyo_catalog.froyo_lakehouse.products
    • PROJECT_ID.froyo_catalog.froyo_lakehouse.feedback_insights
    • PROJECT_ID.froyo_catalog.froyo_lakehouse.sales_history
  4. לוחצים על צ'אט.

שואלים שאלות כדי ליצור תחזית ביקוש ולהעריך את ההשקה

תשאל סדרת שאלות בשפה טבעית כדי לענות על שלוש השאלות העסקיות לגבי השקת Midnight Swirl:

  1. בשדה Ask a question (שליחת שאלה), מזינים את ההנחיה הבאה כדי לבדוק את פרטי המוצר של Midnight Swirl ואת המשוב של הלקוחות, ואז לוחצים על send_spark Send (שליחה):

    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, כששלושה מתוך שישה לקוחות מתכוונים לקנות אותו שוב, ומדגישה חששות לגבי תיוג של אלרגנים של סויה ומרירות של שוקולד מריר.

  2. מזינים את ההנחיה הבאה כדי לחזות את הביקוש ל-12 חודשים עבור הטעמים הקיימים, ואז לוחצים על send_spark שליחה:

    Forecast monthly sales by flavor for the next 12 months, plotting only the
    trend lines without confidence intervals.
    

    ניתוח נתוני השיחות מריץ שאילתה עם AI.FORECAST, שמשתמשת במודל TimesFM המובנה ב-BigQuery ML בלי לאמן מודל נפרד, ומציגה תרשים של התחזית ל-12 חודשים לכל טעם.

  3. מזינים את ההנחיה הבאה כדי לשלב את תחזית הביקוש עם משוב מלקוחות ולקבל המלצות להשקה, ואז לוחצים על 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.
    
  4. אופציונלי: כדי לבדוק את שאילתת ה-SQL שנוצרה או לראות את שלבי ההיגיון של הסוכן, מרחיבים את האפשרות הצגת תהליך החשיבה.

מכאן אפשר לשאול שאלות המשך בשיחה (למשל, פירוט התחזית לפי אזור) או ללחוץ על יצירת סוכן בחלונית פרטים כדי לשמור ולשתף עם הצוות סוכן נתונים שאפשר להשתמש בו שוב.

הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם במדריך הזה, אתם יכולים למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים הספציפיים.

מחיקת הפרויקט

  1. במסוף Google Cloud , נכנסים לדף Manage resources.

    כניסה לדף Manage resources

  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מחיקת משאבים בודדים

אם אתם רוצים לשמור את הפרויקט, אתם צריכים למחוק את המשאבים הבודדים שיצרתם.

  1. כדי למחוק את השיחה, בחלונית העריכה של BigQuery Studio, בוחרים בכרטיסייה סוכנים. בחלונית הניווט שמימין, שאולי תצטרכו להרחיב, מוצאים את השיחה בקטע שיחות מהזמן האחרון, ואז לוחצים על more_vert הצגת הפעולות > מחיקה.

  2. ב-Cloud Shell, מוחקים את ארבע הטבלאות, את מרחב השמות, את הקטלוג ואת הקטגוריה של 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, אפשר לעיין במקורות המידע הבאים: