החדרת רעש

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

מהם היתרונות של הוספת רעש

פתרון בעיות פשוט יותר: השורות מושמטות רק בגלל דרישות צבירה, ולכן קל יותר לפתור בעיות ולהתאים שאילתות.

אין תחביר חדש שצריך ללמוד: לא צריך ללמוד תחביר חדש של שאילתות או להכיר מושגים שקשורים לפרטיות כדי להשתמש ברעש.

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

איך רעשים משפיעים על דרישות הפרטיות

דרישה לצבירה: נתוני החשיפות שמופקים מהוספת רעשי רקע מייצגים כ-20 משתמשים ייחודיים או יותר, ונתוני הקליקים או ההמרות מייצגים כ-10 משתמשים ייחודיים או יותר.

בדיקות סטטיות: אין השפעה.

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

מידע נוסף על בדיקות פרטיות

איך הוספת רעש משפיעה על התוצאות

מערכת Ads Data Hub מוסיפה רעשי רקע כדי לצמצם את הסיכון לחשיפת מידע – הסיכון שמישהו יוכל ללמוד מידע על משתמש ספציפי. הוא מאזן בין פרטיות לבין שימושיות.

הוספת רעשי רקע ב-Ads Data Hub משנה את תוצאות השאילתה באופן הבא:

  • הוא מגביל את התרומות של משתמשים חריגים בתוצאות המצטברות. המודל מסכם את התרומה של כל משתמש בכל צבירה, ואז מגביל כל תרומה באמצעות גבולות הידוק מינימליים ומקסימליים.
  • הוא מסכם את התרומות של כל משתמש אחרי ההגבלה.
  • היא מוסיפה רעש לכל תוצאה מצטברת – התוצאה של כל קריאה לפונקציית צבירה בכל שורה. הקנה מידה של הרעש האקראי הזה הוא יחסי לגבולות המהודקים.
  • היא מחשבת ספירת משתמשים עם רעש לכל שורה ומסירה שורות עם מעט מדי משתמשים (כ-20 משתמשים בכל שורה). בגלל הרעש, משימות שמופעלות באותו מערך נתונים יכולות להשמיט שורות שונות. אפשר להימנע מהדרישה הזו באמצעות קבוצות ציבוריות.

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

מידע על צמצום צבירה

החדרת רעשים ב-Ads Data Hub משתמשת בהצמדה מרומזת או מפורשת של צבירה כדי להגביל את התרומה של חריגים. אתם יכולים לבחור את סוג ההגבלה שבו אתם רוצים להשתמש, בהתאם לתרחיש השימוש.

הגבלה מרומזת

לא צריך להשתמש בתחביר SQL מיוחד כדי להשתמש בהגבלת ערכים משתמעת, היא מופעלת כברירת מחדל. הגבולות המרומזים נגזרים מהנתונים עצמם ונקבעים לכל צבירה. אם בחלק מהצבירות יש טווח ערכים רחב יותר מאשר באחרות, אפשר להסיק גבולות שונים לצבירות שונות לפי הצורך. בדרך כלל זה מוביל לפחות שגיאות. שימו לב: מערכת COUNT(DISTINCT user_id) מגבילה באופן אוטומטי את התרומה של כל משתמש ל-1.

הגבלה מפורשת

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

ב-Ads Data Hub יש ADH.ANONפונקציות מצטברות נוספות לצמצום מפורש. כדי להשתמש בהגבלת ערכים מפורשת, מגדירים את הגבולות לכל פונקציית צבירה נתמכת על ידי הוספת מספרים שלמים שמייצגים את הגבול התחתון והגבול העליון. לדוגמה:

SELECT
campaign_name,
-- Set lower and upper bounds to 0 and 1, respectively
ADH.ANON_COUNT(*, contribution_bounds_per_group => (0,1))
FROM data
GROUP BY 1

הרצת שאילתה באמצעות החדרת רעש

  1. פותחים דוח.
  2. לוחצים על המתג הגדרות "רעש" להגנה על הפרטיות כדי להעביר אותו למצב שימוש ברעש.
  3. מריצים את השאילתה.
  4. בודקים את ההשפעה של הרעש שהוספתם.
  5. אופציונלי: מתאימים את השאילתה כדי לצמצם את ההשפעה של הרעש.

בדיקת ההשפעה של הרעש

אחרי שהעבודה מסתיימת בהצלחה, במערכת Ads Data Hub מוצגת רמת המהימנות של התוצאה בסיכום הפרטיות. המהימנות מבוססת על אחוז התאים בפלט שאולי הושפעו מאוד מרעשי רקע. ערך בטבלת התוצאות נחשב כערך שהושפע אם היקף הרעש שנוסף גדול מ-5% מהתוצאה בתא.

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

% מהתוצאות שהושפעו צבע האינדיקטור השפעה
פחות מ-5% ירוק השפעה נמוכה
‫5% עד 15% צהוב השפעה בינונית
‫15% עד 25% Orange השפעה חזקה
יותר מ-25% אדום השפעה גבוהה מאוד

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

התאמת שאילתות

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

אלה הנחיות כלליות:

  • מרחיבים את טווח התאריכים.
  • לשכתב את השאילתה כדי לצמצם את רמת הפירוט של הנתונים, למשל על ידי קיבוץ לפי פחות פרמטרים או החלפת COUNTIF ב-COUNT.
  • הסרת עמודות עם רעשי רקע.
  • כדאי לנסות הגבלה מפורשת כשניתן לבחור גבולות סבירים.

פונקציות צבירה נתמכות

הפונקציות המצטברות הבאות נתמכות עם רעש:

  • SUM(...)
  • COUNT(*)
  • COUNT(...)
  • COUNTIF(...)
  • COUNT(DISTINCT ...)
  • APPROX_COUNT_DISTINCT(...)
  • AVG(...)

מילת המפתח DISTINCT נתמכת רק בפונקציה COUNT. כשמשתמשים בהן עם הפניה ישירה לעמודה user_id מטבלה ב-Ads Data Hub או עם ביטוי שמחזיר את הערך user_id או NULL, כמו COUNT(DISTINCT IF(..., user_id, NULL)), הפונקציות COUNT DISTINCT ו-APPROX_COUNT_DISTINCT(...) מחושבות על ידי הגבלת התרומה של כל משתמש ל-1. כש-COUNT DISTINCT מפנה לעמודה שהיא לא user_id, היא מחושבת בקירוב באמצעות APPROX_COUNT_DISTINCT עם חסימה מרומזת.

פונקציות צבירה נוספות

בנוסף לתמיכה בפונקציות צבירה רגילות, מערכת Ads Data Hub מציגה פונקציות צבירה משלימות מסוג ADH.ANON שתומכות בהגבלת ערכים מפורשת. הפונקציות האלה משתמשות באותו תחביר כמו פונקציות הצבירה של BigQuery עם פרטיות דיפרנציאלית, אבל לא צריך להשתמש בהן בסעיף WITH DIFFERENTIAL_PRIVACY:

  • ADH.ANON_SUM( ..., [ contribution_bounds_per_group => (lower_bound, upper_bound) ] )

  • ADH.ANON_COUNT( *, [ contribution_bounds_per_group => (lower_bound, upper_bound) ] )

  • ADH.ANON_COUNT( ..., [ contribution_bounds_per_group => (lower_bound, upper_bound) ] )

  • ADH.ANON_AVG( ..., [ contribution_bounds_per_group => (lower_bound, upper_bound) ] )

  • ADH.ANON_PERCENTILE_CONT( ..., percentile, contribution_bounds_per_row => (lower_bound, upper_bound) )

  • ADH.ANON_COUNT_DISTINCT( ..., [ max_contributions_per_group => upper_bound ] )

הפרמטרים ADH.ANON_SUM, ‏ ADH.ANON_COUNT ו-ADH.ANON_AVG:

  • contribution_bounds_per_group: התרומות לכל משתמש מוגבלות לכל מחיצה שמוגדרת על ידי מפתחות GROUP BY. הגבולות העליון והתחתון חלים על ערכים לכל קבוצה אחרי שהערכים מצטברים לכל משתמש.
  • lower_bound: ערך נומרי קבוע שמייצג את הערך הקטן ביותר שייכלל בצבירה.
  • upper_bound: ערך נומרי קבוע שמייצג את הערך הגדול ביותר שייכלל בצבירה.

פרמטרים של ADH.ANON_PERCENTILE_CONT:

  • percentile: האחוזון לחישוב, ערך מילולי בטווח [0, 1].
  • contribution_bounds_per_row: מספר התרומות לכל משתמש מוגבל על בסיס כל שורה (כל רשומה). שימו לב שנדרשים גבולות הידוק מפורשים לאחוזון, ולכן הפונקציה הזו נתמכת רק כפונקציה משלימה.
  • lower_bound: ערך נומרי קבוע שמייצג את הערך הקטן ביותר שייכלל בצבירה.
  • upper_bound: ערך נומרי קבוע שמייצג את הערך הגדול ביותר שייכלל בצבירה.

פרמטרים של ADH.ANON_COUNT_DISTINCT:

  • max_contributions_per_group: התרומות לכל משתמש מוגבלות לכל מחיצה שמוגדרת על ידי מפתחות GROUP BY. הגבול העליון מגביל את התרומה המקסימלית של משתמש לכל קבוצה אחרי צבירת הערכים לכל משתמש.
  • upper_bound: ערך נומרי קבוע שמייצג את הערך הגדול ביותר שייכלל בצבירה.

חישוב הערכים MIN ו-MAX

הפונקציות MIN ו-MAX לא נתמכות ישירות בצבירות של רעשי רקע, אבל לרוב יש שיטות חלופיות לחישוב התוצאות האלה.

אם יש לכם MIN או MAX של ערכים שאפשר להשתמש בהם כמפתחות לקיבוץ, כמו תאריך האירוע, אתם יכולים קודם להשתמש ב-GROUP BY לפי הערך הזה, ואז לחשב את MIN/MAX. הפונקציה מחזירה את הערך המינימלי או המקסימלי שעובר את סף הצבירה.

דוגמה:

WITH campaign_date_ranges AS (
  SELECT campaign_id, MIN(event_date) AS min_date, MAX(event_date) AS max_date
  FROM (
    # Aggregation thresholding will be applied here
    SELECT DISTINCT
      campaign_id,
      DATE(query_id.time_usec, @time_zone) AS event_date
    FROM adh.google_ads_impressions
  )
)
SELECT campaign_id, num_impressions, min_date, max_date
FROM (
  # Noise and aggregation thresholding will be applied here
  SELECT campaign_id, COUNT(*) AS num_impressions
  FROM adh.google_ads_impressions
)
JOIN campaign_date_ranges USING(campaign_id)

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

דוגמה:

SELECT
  campaign_id,
  COUNT(*) AS num_impressions,
  ADH.ANON_PERCENTILE_CONT(
    query_id.time_usec, 0,
    contribution_bounds_per_row => (@min_timestamp, @max_timestamp))
    AS min_timestamp,
  ADH.ANON_PERCENTILE_CONT(
    query_id.time_usec, 1,
    contribution_bounds_per_row => (@min_timestamp, @max_timestamp))
    AS max_timestamp
FROM adh.google_ads_impressions

מידע על תוצאות של מספרים שלמים

מערכת Ads Data Hub תכניס רעשי רקע באופן אוטומטי לפונקציות המצטברות האלה, אבל חתימות הפונקציות לא ישתנו. מכיוון שפונקציות כמו COUNT או SUM של INT64 מחזירות INT64, כל חלק עשרוני של התוצאה עם הרעש מעוגל. בדרך כלל, ההשפעה הזו זניחה ביחס לגודל התוצאה ולרעשי הרקע.

אם אתם צריכים את רמת הפירוט של המספר העשרוני בתוצאה, אל תכתבו פונקציות שמחזירות INT64. לדוגמה, אפשר להשתמש בפונקציה SUM עם קלט שמומר ל-FLOAT64.

מידע על תוצאות שליליות

באופן עקרוני, רעשי רקע עם ערכים קטנים מאוד יכולים להוביל למספרים שליליים, גם אם מבחינה סמנטית זה לא אמור לקרות בשאילתה. כדי לשמור על התנהגות צפויה, כל הצורות של COUNT ו-COUNTIF מוגבלות אוטומטית לאפס, כך שהן אף פעם לא נותנות תוצאות שליליות. אם רוצים להשיג את אותה התנהגות עם פונקציה אחרת, כמו SUM, אפשר להגביל את התוצאות באופן ידני באמצעות GREATEST(0, SUM(...)).

בדרך כלל השינוי הזה זניח, אבל הוא יוצר הטיה חיובית קלה בתוצאות הכוללות.

קבוצות ציבוריות

עם פסקה GROUP BY, התוצאות האנונימיות של שאילתה מצטברות על פני קבוצות. הספים לצבירת נתונים מיועדים לוודא שיש בקבוצה מספר מספיק של משתמשים, כדי להגן על נתונים של משתמשים ספציפיים. התהליך שבו נקבע אילו קבוצות אפשר לשחרר נקרא 'בחירת מחיצה'.

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

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

כדי להיות זכאים לקבוצות ציבוריות, השאילתה צריכה להיות מובנית כך שכל מפתחות הקיבוץ יהיו ידועים מראש. העמודות של הקיבוץ צריכות לעמוד בתנאים הבאים:

  • הם מגיעים מטבלה ציבורית (סעיף table או SELECT ללא נתוני משתמשים ב-Ads Data Hub).
  • הם כוללים את המאפיין SELECT DISTINCT כדי לאכוף ערכים ייחודיים.
  • הם מצורפים לשאילתה עם OUTER JOIN בכל העמודות הנפרדות.

כששאילתה מתאימה לקבוצות ציבוריות, בממשק המשתמש של Ads Data Hub מוצגת הודעת האימות הבאה: 'הפונקציה Join תומכת בקבוצות ציבוריות ולא חלים עליה ספי איחוד'.

דוגמאות לשאילתות של קבוצות ציבוריות:

SELECT age_group_id, COUNT(*) FROM adh.google_ads_impressions
RIGHT OUTER JOIN (SELECT DISTINCT age_group_id FROM adh.age_group)
ON demographics.age_group = age_group_id
GROUP BY age_group_id
SELECT age_group_id, COUNT(*) FROM adh.google_ads_impressions
RIGHT OUTER JOIN (SELECT DISTINCT * FROM UNNEST([1, 2, 3]) AS age_group_id)
ON demographics.age_group = age_group_id
GROUP BY age_group_id

בדוגמה הראשונה, הטבלה המוגנת adh.google_ads_impressions table מצורפת לטבלה adh.age_group שלא מכילה נתוני משתמשים בעמודה age_group_id. אותה עמודה בטבלה הציבורית age_group_id מופיעה בסעיף GROUP BY.

באופן דומה, בדוגמה השנייה, הטבלה המוגנת adh.google_ads_impressions מצורפת לטבלה הציבורית, שמסופקת באופן מפורש בתור UNNEST([1, 2, 3]). שימו לב שבשתי הדוגמאות, מפתח הקיבוץ age_group_id מגיע מהטבלה הציבורית.

אפשר גם לספק כמה פריטים לקיבוץ, לדוגמה:

SELECT campaign_id, COUNT(*) FROM adh.google_ads_impressions
RIGHT OUTER JOIN (SELECT DISTINCT campaign_id, customer_id FROM adh.google_ads_campaign)
USING (campaign_id, customer_id)
GROUP BY campaign_id, customer_id
SELECT p.campaign_id, p.browser, COUNT(*) FROM adh.google_ads_impressions AS i
RIGHT OUTER JOIN (
  SELECT DISTINCT * FROM UNNEST([1, 2]) AS campaign_id
  CROSS JOIN UNNEST(['Chrome', 'Other']) AS browser
) AS p
  ON i.campaign_id = p.campaign_id AND i.browser = p.browser
GROUP BY campaign_id, browser;

כדי ליצור מבנה תקין של RIGHT OUTER JOIN עם שאילתת משנה שמגדירה את הקבוצות הציבוריות, צריך לוודא שההצהרה SELECT DISTINCT בשאילתת המשנה כוללת רק את השדות שמשמשים בסעיף ON של JOIN. אותם שדות צריכים להופיע גם בסעיף GROUP BY של השאילתה הראשית. לדוגמה, השאילתה הבאה לא תעמוד בדרישות של קבוצות ציבוריות:

SELECT age_group_id, COUNT(*) FROM adh.google_ads_impressions
RIGHT OUTER JOIN (
  SELECT DISTINCT * -- Incorrect: May include fields not in the JOIN/GROUP BY
  FROM adh.age_group
)
  ON demographics.age_group = age_group_id
GROUP BY age_group_id

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

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

GROUP BY ROLLUP

GROUP BY ROLLUP מרחיב את הסעיף GROUP BY כך שיכלול שורות נוספות שמייצגות סכומי ביניים וסכומים כוללים על סמך ההיררכיה שמוגדרת ברשימת הקיבוץ. ב-Ads Data Hub, האפשרות GROUP BY ROLLUP זמינה רק כשמשתמשים בהוספת רעשי רקע. התחביר תואם למפרט הסטנדרטי של BigQuery.

סכומים כוללים עקביים בקבוצות ציבוריות

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

כשמשתמשים ב-GROUP BY ROLLUP בשילוב עם קבוצות ציבוריות, מערכת Ads Data Hub תבטל את חוסר העקביות הזה בתוצאות. הסיבה לכך היא שאין תוצאות שמסוננות בגלל הגדרת סף. לדוגמה, סכום הנתונים של הערים יהיה שווה לנתונים של האזור הרלוונטי. (הערה: אם התוצאות הן מספרים שלמים, יכולים להיות הבדלים קלים בגלל שגיאות עיגול של מספרים עשרוניים).

יתרונות השימוש בקבוצות ציבוריות עם ROLLUP

  1. צבירות עקביות: מוודא שהסכומים והסכומים הכוללים תואמים.
  2. שיפור הדיוק: תהליך העקביות משפר את הדיוק הכולל של הנתונים. רמות גבוהות יותר בהיררכיית הסיכום (כמו סיכומים ברמת המדינה) מבוססות על מערכי נתונים גדולים יותר, וההשפעה היחסית של הרעש נוטה להיות קטנה יותר. המידע היציב יותר הזה מרמות גבוהות יותר משמש להתאמה ולשיפור האיכות של הרמות המפורטות יותר (כמו נתונים מצטברים ברמת העיר).

מומלץ מאוד להשתמש ב-GROUP BY ROLLUP עם קבוצות ציבוריות בכל הזדמנות אפשרית כדי ליהנות מהיתרונות האלה.

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

ROLLUP באמצעות מקש יחיד:

שימוש בטבלה:

SELECT country_code, COUNT(1) AS count
FROM adh.google_ads_impressions
RIGHT OUTER JOIN
 (SELECT DISTINCT country_code FROM adh.city)
 ON location.country = country_code
GROUP BY ROLLUP (country_code);

שימוש ברשימה מוטבעת:

SELECT country_code, COUNT(1) AS count
FROM adh.google_ads_impressions
RIGHT OUTER JOIN
 (SELECT DISTINCT * FROM UNNEST(['US', 'CA', 'CN', 'MX']) AS country_code)
 ON location.country = country_code
GROUP BY ROLLUP (country_code);

תוצאה לדוגמה:

country_code מספר יחידות
CN 6155
קנדה 16439
ארה"ב 256695
MX 10780
null 290067

השורה עם NULL עבור country_code מייצגת את הסכום הכולל. סכום הערכים של כל מדינה בנפרד, 290069, קרוב מאוד לערך בשורה של הסכום הכולל, 290067, וההבדל הקטן נובע מעיגול.

ROLLUP עם כמה מפתחות קיבוץ:

SELECT p.campaign_id, p.browser, COUNT(*) as count
FROM adh.google_ads_impressions AS i
RIGHT OUTER JOIN (
 SELECT DISTINCT * FROM UNNEST([1, 2]) AS campaign_id
 CROSS JOIN UNNEST(['Chrome', 'Other']) AS browser
) AS p
 ON i.campaign_id = p.campaign_id AND i.browser = p.browser
GROUP BY ROLLUP (campaign_id, browser);

תוצאה לדוגמה:

campaign_id דפדפן מספר יחידות הערות
1 Chrome ...
1 אחר ...
2 Chrome ...
2 אחר ...
1 null ... Subtotal for campaign_id = 1
2 null ... סכום ביניים עבור campaign_id = 2
null null ... סכום כולל

ROLLUP עם קבוצות פריטים שאפשר לקבץ:

כדי להתייחס לכמה עמודות כיחידה אחת בהיררכיית הסיכום, מקיפים אותן בסוגריים, לדוגמה: ROLLUP ((column1, column2), column3). הנתונים מצטברים לפי זוג (campaign_id, browser) כישות אחת.

GROUP BY ROLLUP ((campaign_id, browser)) יציג סיכומי ביניים של:

  • (campaign_id, browser) – רמת הפירוט הגבוהה ביותר
  • () – סכום כולל

לא ייווצרו סכומי ביניים רק עבור (campaign_id).

SELECT p.campaign_id, p.browser, COUNT(*) AS count
FROM adh.google_ads_impressions AS i
RIGHT OUTER JOIN (
 SELECT DISTINCT * FROM UNNEST([1, 2]) AS campaign_id
 CROSS JOIN UNNEST(['Chrome', 'Other']) AS browser
) AS p
 ON i.campaign_id = p.campaign_id AND i.browser = p.browser
GROUP BY ROLLUP ((campaign_id, browser));

תוצאה לדוגמה:

campaign_id דפדפן מספר יחידות הערות
1 Chrome ...
1 אחר ...
2 Chrome ...
2 אחר ...
null null ... סכום כולל

הערה: שימוש ב-ROLLUP עם הרבה רמות היררכיות או עם מספר גדול של ערכים שונים במפתחות הקיבוץ יכול ליצור מספר גדול של שורות פלט. זה עלול להוביל לשגיאות בגלל המגבלות של Ads Data Hub על תוצאות חוזרות. מומלץ להגביל את מספר הרמות ההיררכיות ואת הקרדינליות של מפתחות הקיבוץ.


דפוסי שאילתות נתמכים

חשוב: רוב השיטות המומלצות הרגילות של Ads Data Hub עדיין רלוונטיות לשאילתות שמשתמשות בהוספת רעש. בפרט, מומלץ לעיין בהנחיות בנושא שליחת שאילתות חוזרות לגבי אותם נתונים.

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

נתונים מצטברים ברמת המשתמש

הוספת הרעש מתבצעת רק בצבירות שמשלבות נתונים מכמה משתמשים. צבירות שמקובצות או מחולקות במפורש לפי user_id לא מקבלות רעש ולא מגבילות את השימוש בפונקציה. צבירות ברמת המשתמש שלא מקובצות במפורש לפי user_id, לדוגמה GROUP BY impression_id, נחשבות לצבירות של נתונים של כמה משתמשים, ולכן מתווסף רעש.

קיבוץ לפי external_cookie לא מספיק. אפשר להשתמש ב-external_cookie כדי לצרף טבלאות *_match לטבלאות בבעלות הלקוח, אבל כשמבצעים צבירה של נתונים של משתמש יחיד, צריך לקבץ במפורש לפי העמודה user_id, ולא רק לפי העמודה external_cookie.

דוגמה לפונקציית צבירה:

WITH user_paths AS (
  # Grouping by user_id, no noise needed, all functions allowed
  SELECT user_id, STRING_AGG(campaign_id, ">" ORDER BY query_id.time_usec) AS path
  FROM adh.google_ads_impressions
  GROUP BY 1
)
# Noise applied here to num_users
SELECT path, COUNT(*) AS num_users
FROM user_paths
GROUP BY 1;

דוגמה לפונקציה אנליטית:

WITH events AS (
  # Partitioning by user_id, no noise needed, all functions allowed
  SELECT
    campaign_id,
    ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY query_id.time_usec) AS index
  FROM adh.google_ads_impressions
)
# Noise applied here to first_impressions
SELECT campaign_id, COUNT(*) AS first_impressions
FROM events
WHERE index = 1
GROUP BY 1;

צבירות מקבילות

כל צבירה של נתונים של כמה משתמשים מקבלת רעשי רקע באופן עצמאי. אפשר להריץ כמה צבירות כאלה בהצהרה אחת, ולשלב את התוצאות בטבלה אחת באמצעות JOIN או UNION.

דוגמה:

WITH result_1 AS (
  # Noise applied here to num_impressions
  SELECT campaign_id, COUNT(*) AS num_impressions
  FROM adh.google_ads_impressions
  GROUP BY 1
), result_2 AS (
  # Noise applied here to num_clicks
  SELECT campaign_id, COUNT(*) AS num_clicks
  FROM adh.google_ads_creative_conversions
  GROUP BY 1
)
SELECT * FROM result_1 JOIN result_2 USING(campaign_id)

נתונים נצברים שמאוחדים עם נתונים לא נצברים

מכיוון שמערכת Ads Data Hub תומכת רק בחלונות ניתוח שמחולקים לפי user_id, פתרון נפוץ הוא לצבור את התוצאות האלה בנפרד ולבצע עליהן צירוף עצמי לפני צבירה נוספת.

דוגמה:

WITH campaign_totals AS (
  # Noise applied here to campaign_imps
  SELECT campaign_id, COUNT(*) AS campaign_imps
  FROM adh.google_ads_impressions
  GROUP BY 1
)
# Noise applied here to imps
SELECT campaign_id, demographics, campaign_imps, COUNT(*) AS imps
FROM adh.google_ads_impressions JOIN campaign_totals USING(campaign_id)
GROUP BY 1,2,3

מצב הרעש מונע צבירה מחדש של תוצאות מצטברות, כמו AVG(campaign_imps).


תבניות שאילתה לא נתמכות

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

תוצאות חוזרות

במצב רעש, מערכת Ads Data Hub מגבילה את התדירות שבה אפשר לחזור על אותה צבירה. אם תגיעו למגבלות האלה, השאילתות במצב הרעש לא יוכלו לגשת לתאריכים שנכללים בשאילתות לעיתים קרובות במערך הנתונים. בהמשך מפורטות כמה דוגמאות לאופן שבו זה יכול לקרות.

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

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

SELECT DATE(TIMESTAMP_MICROS(event.event_time)) AS date,
COUNT(*) AS cnt
FROM adh.cm_dt_clicks
GROUP BY 1

במקרה כזה, כדאי להריץ את השאילתה על פלחי תאריכים לא חופפים.

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

SELECT campaign_id, COUNT(*) AS cnt
FROM adh.google_ads_impressions
GROUP BY 1

במקרה כזה, כדאי להריץ את השאילתה רק פעם אחת כי התוצאה לא משתנה.

חזרה על צבירה מתרחשת כשאותה צבירה חוזרת על עצמה כמה פעמים בשאילתה:

SELECT COUNT(*) AS cnt1, COUNT(*) AS cnt2
FROM table

במקרה כזה, צריך להסיר את אחת החזרות.

שימו לב: גם אם הצבירות שונות מבחינת התחביר אבל מחשבות את אותו ערך, הן ייחשבו כחזרה. במילים אחרות, אם הערכים של condition1 ו-condition2 זהים לכל המשתמשים עם ערך מסוים של key, השאילתה הבאה תחזור על עצמה:

SELECT key, COUNTIF(condition1) AS cnt1, COUNTIF(condition2) AS cnt2
FROM table
GROUP BY key

אם יש לכם תנאים דומים מאוד לכמה קבוצות של משתמשים, כדאי לשקול לכתוב מחדש את השאילתה כך שתכלול רק COUNT אחד.

שכפול שורות מתרחש כשמצטרפים לטבלה ב-Ads Data Hub טבלה ב-BigQuery באופן שבו כל שורה מהטבלה ב-Ads Data Hub תואמת לכמה שורות בטבלה ב-BigQuery. לדוגמה, השאילתה הבאה יוצרת חזרה אם יש כמה שורות עם אותו מזהה קמפיין ב-bq_table:

SELECT r.campaign_id, COUNT(*) AS cnt
FROM adh_table
INNER JOIN bq_table ON l.campaign_id = r.campaign_id

במקרה כזה, צריך לשנות את מבנה השאילתה כך שלכל ערך של מפתח הצירוף (campaign_id במקרה הזה) יהיה רק שורה אחת ב-bq_table.

שימו לב: ביטול הקינון של מערך מטבלה ב-Ads Data Hub יכול להניב את אותו אפקט אם לרוב המשתמשים יש את אותם מערכים של ערכים:

SELECT in_market_id, COUNT(*)
FROM adh.dv360_youtube_impressions,
UNNEST(in_market) AS in_market_id
GROUP BY 1

ככלל, מומלץ להגביל את החישוב של אותן תוצאות ל-10 פעמים או פחות. ככל שתתקרבו לסף, יוצגו אזהרות ב-Ads Data Hub. אם אותן תוצאות ימשיכו להיות מחושבות מעבר לסף, העבודות שלכם ייחסמו ויוצגו שגיאות.

מידע נוסף על שיטות מומלצות לשאילתות

מידע על חלונות מבט לאחור

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

לדוגמה, אם יוצרים דוח של מדדים לפי תאריך, שמתעדכן מדי יום:

SELECT
  campaign_id,
  DATE(TIMESTAMP_MICROS(query_id.time_usec), @time_zone) AS event_date,
  COUNT(*) AS impressions
FROM adh.google_ads_impressions
GROUP BY 1,2

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

עדיין אפשר לחשב מחדש טווחי תאריכים קודמים כדי לרענן את התוצאות (לדוגמה, כדי להתחשב בנתונים שהגיעו באיחור), אבל כדאי להימנע מחישוב מחדש של תוצאה יחידה יותר מדי פעמים, כמו שמתואר קודם.

צבירה מחדש ישירה

רעש מוחל על השכבה הראשונה של צבירת נתונים בין משתמשים בשאילתה. שאילתות עם כמה שכבות של צבירה ישלבו תוצאות עם רעשי רקע, ולכן יכול להיות שרעשי הרקע בצבירות הסופיות יהיו גבוהים בהרבה. השאילתות האלה מקבלות אזהרה באימות:

WITH layer_1 AS (
  # Noise applied here to partial_result
  SELECT campaign_id, demographics, location, COUNT(*) AS partial_result
  FROM adh.google_ads_impressions
  GROUP BY 1,2,3
  HAVING partial_result > 5
)
# Reaggregation of partial_result with no user-level data, will be rejected
SELECT campaign_id, SUM(partial_result) AS final_result
FROM layer_1
GROUP BY 1

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

אם אי אפשר להימנע מצבירה רב-שכבתית, אפשר לפתור את האזהרה על ידי ייצוא התוצאות ישירות מהשכבה הראשונה. כדי לעשות את זה במשימה אחת בלי לשנות את תוצאות הסקריפט, יוצרים טבלה זמנית (או טבלה שמיוצאת לפרויקט BigQuery) באמצעות התחביר OPTIONS(privacy_checked_export=true). לדוגמה:

CREATE TEMP TABLE layer_1 OPTIONS(privacy_checked_export=true) AS (
  # Noise applied here to partial_result
  SELECT campaign_id, demographics, location, COUNT(*) AS partial_result
  FROM adh.google_ads_impressions
  GROUP BY 1,2,3
  HAVING partial_result > 5
);
# Reaggregation of privacy checked data, no noise needed
SELECT campaign_id, SUM(partial_result) AS final_result
FROM layer_1
GROUP BY 1

מידע נוסף על טבלאות זמניות

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

מזהי משתמשים שלא צורפו

שאילתות במצב רעש לא יכולות לשלב נתונים ממשתמשים שונים בשורה אחת, אלא אם מתבצעת צבירה עם רעש. לכן, כשמבצעים הצטרפות של נתונים לא מצטברים מ-Ads Data Hub, צריך להצטרף במפורש לעמודה user_id.

השאילתה הזו לא מצטרפת באופן מפורש לעמודה user_id, ולכן מוצגת אזהרת אימות:

SELECT 
FROM adh.google_ads_impressions
JOIN adh.google_ads_creative_conversions USING(impression_id)

יכול להיות שצירופים כאלה לא יתנהגו כמו שמצפים כי רק שורות עם אותו ערך user_id יתאימו. כדי לפתור את הבעיה, צריך לשנות את סעיף USING כך שיכלול במפורש את user_id – לדוגמה, USING(impression_id, user_id).

שימו לב שההגבלה הזו חלה רק על שאילתות איחוד (join) בין טבלאות ב-Ads Data Hub (למעט טבלאות מאפיינים). היא לא חלה על טבלאות בבעלות הלקוח. לדוגמה, מותר לפרסם:

SELECT 
FROM adh.google_ads_impressions
JOIN bigquery_project.dataset.table USING(any_column)

צירופים חיצוניים ימניים (right joins) ב-Ads Data Hub-BigQuery

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

שתי השאילתות האלה מובילות לאזהרות אימות כי הן מאפשרות שורות לא תואמות עם מזהי משתמשים חסרים בצד של Ads Data Hub:

SELECT 
FROM adh.google_ads_impressions
RIGHT JOIN bigquery_project.dataset.table USING(column)
SELECT 
FROM bigquery_project.dataset.table
LEFT JOIN adh.google_ads_impressions USING(column)

שימו לב: אם סדר הטבלאות היה הפוך, כל אחת מההצטרפויות הייתה עובדת. יש גם חריג לטבלאות RDID שמצטרפות ישירות ל-device_id_md5. לדוגמה, השאילתה הבאה תפעל ללא אזהרות:

SELECT 
FROM bigquery_project.dataset.table
LEFT JOIN adh.google_ads_impressions_rdid USING(device_id_md5)

סיכום השורות שסוננו

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

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

SELECT campaign_name, COUNT(*)
FROM data
GROUP BY 1
UNION ALL
SELECT 'Total', COUNT(*)
FROM data
GROUP BY 1

שימו לב שהספירה הכוללת עוברת רעש באופן עצמאי, ולכן יכול להיות שהערכים הכוללים לא יסתכמו, אבל הספירה הכוללת לרוב מדויקת יותר מאשר סכום השורות שעברו רעש.

טבלאות שנוצרו במצב מעורב

אפשר להשתמש בטבלאות שלא יוצאו ב-Ads Data Hub רק באותו מצב פרטיות שבו הן נוצרו. אי אפשר ליצור טבלה במצב צבירה רגיל ולהשתמש בה במצב רעש, או להיפך (אלא אם הטבלה הזו מיוצאת קודם ל-BigQuery).