ノイズ インジェクションは、データベースにクエリを実行する際にユーザーのプライバシーを保護するために使用される技術です。これは、クエリの集計 SELECT
句にランダムノイズを追加することで機能します。このノイズによりユーザーのプライバシーが保護される一方で、ある程度の正確な結果が得られ、差分チェックの必要性がなくなり、出力に必要な集計しきい値が削減されます。いくつかの制限があるものの、既存のクエリのほとんどはノイズモードで実行できます。
ノイズ インジェクションを使用する利点を学ぶ
差分チェックが適用されない: ノイズ インジェクションを使用してクエリを実行すると、前の結果セットとの類似性による行のフィルタリングが行われません。この特長により、ユーザーのプライバシーを保護しながら、包括的なデータを取得できます。
トラブルシューティングが簡素化される: 行は集計要件によってのみ省略されるため、クエリのトラブルシューティングと調整が簡単になります。
新しい構文を学習する必要がない: 差分チェックの代わりにノイズを使用するために、新しいクエリ構文を学習したり、プライバシー概念に精通したりする必要はありません。
結果の精度が明確になる: ジョブが成功すると、ノイズ量が予想内であったデータの合計パーセンテージが表示されます。
ノイズがプライバシー要件に与える影響を学ぶ
差分チェック: ノイズ インジェクションは、Ads Data Hub の既存の差分チェックに依存しません。ノイズ インジェクションを使用する場合、差分チェックは無効になります。
集計要件: ノイズ インジェクションでは、インプレッション データを出力するには約 20 人以上のユニーク ユーザー、クリックデータまたはコンバージョン データを出力するには約 10 人以上のユニーク ユーザーが必要です。
静的チェック: 影響はありません。
予算とクエリ制限: ノイズを使用して実行されたクエリは、差分チェックで使用されるデータアクセス予算を共有します。差分チェックと同様に、同じデータセットに対して同じクエリを何度も実行すると、データセット内の頻繁にクエリされる日付にアクセスできなくなる可能性があります。これは、スライディング ウィンドウ クエリを実行する場合、または同じリクエストを複数回実行する場合に発生する可能性があります。
ノイズモードでは、クエリ内またはクエリ間で同じ集計結果を再計算する場合に、さらに厳しい制限が課されます。データアクセス予算と同様に、データセット内の頻繁にクエリされる日付にアクセスできなくなる可能性があります。ただし、同じ集計結果を再計算することによる制限は、ノイズモードのクエリのみに適用され、差分チェックモードのクエリには適用されません。詳しくは、繰り返し結果をご覧ください。
プライバシー チェックについて詳しくは、こちらをご覧ください。
ノイズ インジェクションが結果に与える影響を理解する
Ads Data Hub では、開示リスク(個人ユーザーに関する情報が第三者に知られるリスク)を軽減するために、プライバシーと実用性のバランスをとりながらノイズが注入されます。
Ads Data Hub のノイズ インジェクションにより、クエリ結果が次のように変換されます。
- 集計結果における「外れ値」ユーザーの貢献度を境界内に収めます。各集計における各ユーザーの貢献度を合計し、最小および最大のクランプ境界に各貢献度が収まるようにします。
- 範囲内にあるユーザーごとの貢献度を集計します。
- 各集計結果(各行の各集計関数呼び出しの結果)にノイズが追加されます。このランダムノイズのスケールは、クランプ境界に比例します。
- ノイズが加えられた各行のユーザー数が集計され、ユーザー数が少なすぎる行が削除されます。これは差分チェックモードの k-匿名性と似ていますが、ノイズを使用しているため、同じデータセット上で実行されているジョブにより異なる行が削除される可能性があります。 また、ノイズモードでは、集計要件が低い(正確に 50 行ではなく約 20 行)ため、削除される行が少なくなります。
最終結果となるデータセットでは、ノイズが加えられた各行が集計され、小さなグループが除外されています。これにより、返された結果で個々のユーザーの影響がマスクされます。
集計クランプについて
Ads Data Hub のノイズ インジェクションでは、暗黙的または明示的な集計クランプを使用して、外れ値の貢献度を制限します。ユースケースに応じて、使用するクランプのタイプを選択できます。
暗黙的なクランプ
暗黙的なクランプでは、境界が自動的に決定されます。暗黙的なクランプを使用するために特別な SQL 構文は必要ありません。暗黙的な境界では、値の範囲が別の行よりも広い行に対して異なる境界が取得されます。 これにより、通常、各結果の誤差が小さくなります。ただし、集計ごとにクランプ境界とノイズレベルが異なってしまうため、比較が困難になる可能性があります。
少数のユーザーからのデータを集計する場合(まれな条件を持つ COUNTIF()
呼び出しなど)、暗黙的なクランプが失敗し、NULL
結果が返される可能性があります。また、0
および 1
の境界を持つ明示的なクランプが COUNT(DISTINCT user_id)
で自動的に使用されることもあります。
明示的なクランプ
明示的なクランプでは、指定された範囲内に各ユーザーからの合計貢献度が収められます。明示的な境界(リテラル値で設定)は、すべての行に均一に適用されます。一部の行のユーザーごとの貢献度の範囲が他の行よりも広い場合でも、すべての行に同じ境界が適用されます。これにより、異なる行からの結果の比較が容易になりますが、一部の行では暗黙的なクランプよりも多くのノイズが発生します。
明示的なクランプでは、指定された一連のクランプ範囲に対して、暗黙的なクランプの半分のノイズが使用されます。したがって、適切な境界を推定できる場合は、明示的に設定する方がより良い結果が得られます。
明示的なクランプを使用するには、下限と上限を表す整数を追加して、サポート対象の各集計関数の境界を設定します。次に例を示します。
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
ノイズ インジェクションを使用してクエリを実行する
- クエリを記述するか既存のクエリを開きます。使用可能な集計関数については、サポート対象の関数でご確認ください。
- クエリエディタで、[実行]をクリックし、新しいジョブの詳細を入力します。
- [プライバシー設定] をクリックし、[ノイズを使用] に切り替えます。
- クエリを実行します。
- 追加されたノイズを確認します。
- 省略可: クエリを調整して、ノイズの影響を軽減します。
ノイズの影響を確認する
クエリが正常に完了すると、ノイズ量が予想内であった出力のセルの数に基づいて、結果の信頼性が表示されます。結果テーブルの値に追加されたノイズのスケールがセル内の結果の 5% を超える場合、その値は大きな影響を受けていると見なされます。次の表の影響範囲を参照してください。
影響を受けている出力データセットの詳細タブには、影響が最も大きい列から順番にノイズが最も多い 10 列が、それに対応するノイズへの貢献度とともにリストされます。 以下の表は、量が予想内であるノイズの内訳です。
ノイズ量が予想内のデータ | インジケーターの色 | 影響 |
---|---|---|
>95% | 緑 | 影響が小さい |
85~95% | 黄 | 影響が中程度 |
75~85% | オレンジ | 影響が大きい |
<75% | 赤 | 影響が非常に大きい |
ノイズの影響に関する詳細情報を表示するには:
- [レポート] をクリックします。
- リストからレポートを選択します。プライバシー概要ツールチップには、ノイズ量が予想内(結果の 5% を超えて追加されたノイズ量)だった結果の割合が示されます。
- 詳細情報を確認するには、[ジョブ] > [詳細] をクリックします。
- ジョブの詳細で、[プライバシーに関するメッセージ] を確認します。結果は、リストされているカテゴリのいずれかに分類されます。
- 結果を改善するために、必要に応じてクエリを調整します。
クエリを調整する
集計結果に貢献するユーザーがほとんどいない場合、集計結果には予想外の量のノイズが含まれる可能性が高くなります。これは、行にユーザーがほとんどいない場合、または一部のユーザーが結果に影響を与えない場合(COUNTIF
関数の使用時など)に発生する可能性があります。ノイズの詳細に基づいてクエリを調整することで、ノイズ量が予想内のデータの割合を増やすことができます。
一般的なガイドラインは次のとおりです。
- 期間を延長します。
- グループ化の基となるパラメータの数を減らしたり
COUNTIF
をCOUNT
で置き換えたりすなど、クエリを書き直してデータの粒度を下げます。 - ノイズの多い列を削除します。
- 明示的なクランプを使用します。
サポート対象の集計関数
次の集計関数ではノイズの使用がサポートされています。
SUM(...)
COUNT(*)
COUNT(...)
COUNTIF(...)
COUNT(DISTINCT user_id)
APPROX_COUNT_DISTINCT(user_id)
AVG(...)
DISTINCT
キーワードは、COUNT
関数でのみサポートされています。また、Ads Data Hub テーブルの user_id
列への直接参照、または user_id
か NULL
を返す式(COUNT(DISTINCT IF(..., user_id, NULL))
など)でのみ使用する必要があります。
次の関数は直接にはサポートされていませんが、ノイズを含む他の集計に置き換えて統計結果を得ることができます。数値は単なる例であることにご注意ください。
LOGICAL_OR(...)
。推奨される置き換え:COUNT(DISTINCT IF(..., user_id, NULL)) > 0
LOGICAL_AND(...)
。推奨される置き換え:COUNT(DISTINCT IF(NOT ..., user_id, NULL)) <= 0
整数の結果について
Ads Data Hub は上記の集計関数に自動的にノイズを挿入しますが、関数の署名は変更されません。INT64
の COUNT
または SUM
のような関数は INT64
を返すため、ノイズが含まれた結果の小数部分は四捨五入されます。丸められた数値は通常、結果とノイズのサイズに比べると無視できる程度のものです。
結果に小数点の粒度が必要な場合は、INT64
を返す関数を作成せずに、たとえば、入力を FLOAT64
にキャストする SUM
を使用します。
サポートされているクエリパターン
重要: Ads Data Hub のほとんどの標準的なベスト プラクティスは、ノイズ インジェクションを使用するクエリにも適用されます。特に、同じデータの繰り返しクエリに関するガイダンスをご確認ください。
このセクションでは、ノイズ インジェクションを使用してクエリを実行するときにサポートされるクエリパターンについて説明します。
ユーザーレベルの集計
ユーザーレベルでの無制限の集計は、差分チェックモードの場合と同じ方法でサポートされます。ノイズは、複数のユーザーにわたるデータを結合する集計にのみ注入されます。user_id
で明示的にグループ化する集計、または user_id
でパーティショニングする分析関数はノイズを受け取らず、どの関数も許可されます。user_id
ごとに明示的にグループ化されていないユーザーレベルの集計(例: GROUP BY impression_id
)は、ユーザー間の集計として扱われるため、ノイズが追加されます。
external_cookie ごとにグループ化するだけでは十分ではありません。external_cookie を使用して *_match テーブルと顧客所有のテーブルを結合することはできますが、単一ユーザーの集計は、external_cookie 列だけでなく user_id 列で明示的にグループ化する必要があります。
集計関数の例:
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;
並行集計
クロスユーザーの各集計は、独立してノイズを受け取ります。このような複数の集計は、1 つのステートメントで実行し、JOIN
または UNION
を使用して結果を 1 つのテーブルに結合できます。
例:
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_clicks
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 プロジェクトにエクスポートされているデータを使用することで回避できます。
2 つのジョブが重複する期間をクエリしている場合、同じユーザーに対して同じ計算を実行すると、繰り返しが発生する可能性があります。たとえば、重複する期間に対して実行される次のクエリは、日付でパーティショニングされているため、繰り返しが発生します。
SELECT DATE(TIMESTAMP_MICROS(event.event_time)) AS date,
COUNT(*) AS cnt
FROM adh.cm_dt_clicks
GROUP BY 1
この場合、重複していない日付セグメントに対してクエリを実行する必要があります。
繰り返しが発生する別の例は、データが日付にあまり依存していない場合です。 次のクエリは、キャンペーンの全期間をカバーしている 2 つのジョブを重複する日付に実行すると、繰り返しが生成されます。
SELECT campaign_id, COUNT(*) AS cnt
FROM adh.google_ads_impressions
GROUP BY 1
この場合、結果は変わらないため、このクエリは 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
を 1 つだけ持つようにクエリを書き直してください。
行の重複は、Ads Data Hub テーブルの各行が BigQuery テーブル内の複数の行と一致するような方法で、Ads Data Hub テーブルが BigQuery テーブルと結合されるときに発生します。たとえば、次のクエリでは、同じキャンペーン ID を持つ行が 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
)ごとに 1 行だけ 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
クエリの他のベスト プラクティスについては、こちらをご覧ください。
直接再集計
ノイズは、クエリ内のクロスユーザー集計の最初のレイヤに適用されます。 複数の集計レイヤを含む次のようなクエリはブロックされます。
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
を取得します。クエリを書き換えてノイズのある集計を再集計することは可能ですが、最終的な集計にはノイズがかなり多くなる可能性があります。
これが避けられない場合は、代わりに最初のレイヤーから結果を直接エクスポートするようにクエリを書き直すことができます。スクリプトの結果を変更せずにこれを 1 つのジョブ内で行うには、OPTIONS(privacy_checked_export=true)
構文で一時テーブル(または BigQuery プロジェクトにエクスポートされたテーブル)を作成します。次に例を示します。
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
一時テーブルについて詳しくは、こちらをご覧ください。
集計の最初のレイヤがプライバシー チェックには粒度が高すぎる場合は、ユーザーレベルの集計を使用してクエリを書き直すことができます。これが不可能な場合、このクエリはノイズモードでは実行できません。
結合されていないユーザー ID
ノイズモードのクエリでは、ノイズを使用して集計を実行する場合を除き、別々のユーザーからのデータは 1 つの行に結合されません。そのため、未集計の Ads Data Hub データを結合するには、user_id
列で明示的に結合する必要があります。
以下のクエリは user_id
列に対して明示的に結合していないため、検証エラーが発生します。
SELECT …
FROM adh.google_ads_impressions
JOIN adh.google_ads_clicks USING(impression_id)
このエラーは、USING
句を調整して user_id
を明示的に含めること(例: USING(impression_id, user_id)
)で修正できます。
なお、この制限は Ads Data Hub テーブル間の結合にのみ適用されます(ディメンション テーブルを除く)。顧客所有のテーブルには適用されません。たとえば、次は許可されています。
SELECT …
FROM adh.google_ads_impressions
JOIN bigquery_project.dataset.table USING(any_column)
Ads Data Hub と BigQuery の合併
ノイズを使用する集計が適切に機能するには、ユーザー識別子が必要です。BigQuery 内の顧客所有データにはユーザー識別子がないため、Ads Data Hub テーブルに結合しない限りノイズ集計に結合することはできません。
このようなクエリでは検証エラーが発生します。
SELECT COUNT(*) FROM (
SELECT 1 FROM adh.google_ads_impressions
UNION ALL
SELECT 1 FROM bigquery_project.dataset.table
)
これを修正するには、BigQuery テーブルを合併するのではなく結合することで Ads Data Hub データを拡張するか、データを分離して各ソースを個別に集計する必要があります。
なお、ユーザーデータを含む複数の Ads Data Hub テーブル間、または顧客所有の複数の BigQuery テーブル間で合併集合を取得することは問題ありませんが、この 2 つを混合することはできません。
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)
なお、テーブルの順序が逆であったとしたら、どちらの結合も機能します。
フィルタされた行の概要
フィルタされた行の概要仕様は、ノイズモードではサポートされていません。ノイズモードではフィルタリング レートが低く、差分チェックによるフィルタリングが発生しないため、ほとんどの場合この機能は不要です。
ノイズ結果で重要なデータ フィルタリングが観察された場合は、集計データを増やします。データセット全体に対して並行集計を実行して、合計の推定値を比較できます。次に例を示します。
SELECT campaign_name, COUNT(*)
FROM data
GROUP BY 1
UNION ALL
SELECT 'Total', COUNT(*)
FROM data
GROUP BY 1
合計数には独立してノイズが含まれており、合計値が加算されない場合がありますが、多くの場合、ノイズが含まれた行の合計を取得するよりも合計数の方が正確になります。
クロスモードで作成されたテーブル
エクスポートされていない Ads Data Hub テーブルは、テーブルが作成されたときと同じプライバシー モードでのみ使用できます。最初に BigQuery にエクスポートされていない限り、通常の集計モードで作成したテーブルをノイズモードで使用することはできません。その逆も同様です。