干扰数据注入

噪声注入是在查询数据库时用于保护用户隐私的一种技术,其工作原理是在查询的 SELECT 汇总子句中添加随机噪声。这种噪声可以保护用户隐私,同时提供相对准确的结果,为您省去进行差异检查的麻烦,并降低输出所需的汇总阈值。大多数的现有查询都可以在噪声模式下执行,但存在一定的限制

了解使用噪声注入功能的好处

无需进行差异检查:如果在运行查询时使用噪声注入功能,广告数据中心不会因为与之前的结果集类似而滤除某些行。这意味着,您在保护用户隐私的同时,仍然可以全面了解数据。

简化问题排查流程:系统只会为了满足汇总要求而省略一些行,这使得问题排查和调整查询变得更简单。

无需学习新语法:您无需学习任何新的查询语法,也无需精通隐私权概念,就能使用噪声来取代差异检查。

容易确定结果的准确性:成功执行作业后,您会看到包含预期噪声量的数据所占的总百分比。

了解噪声如何影响隐私权要求

差异检查:噪声注入不依赖于广告数据中心内现有的差异检查。当您使用噪声注入功能时,差异检查将会停用。

汇总要求:噪声注入功能会输出展示数据(以大约 20 位或更多唯一身份用户作为代表),以及点击或转化数据(以大约 10 位或更多唯一身份用户作为代表)。

静态检查:没有任何影响。

预算和查询限制:使用噪声注入功能执行的查询会与差异检查共用数据访问预算。与差异检查一样,如果您多次针对同一数据集执行相同查询,则可能无法访问数据集中经常查询的日期。如果您运行滑动窗口查询或多次发出相同的请求,就可能会出现上述情况。

在查询中或跨查询重新计算相同的汇总结果时,噪声模式会施加更为严格的额外限制。与数据访问预算一样,您可能无法访问数据集中经常查询的日期;但是,由于重新计算相同的汇总结果而产生的限制只会限制噪声模式下的查询,而不会限制差异检查模式下的查询。如需了解详情,请参阅重复结果

详细了解隐私权检查

了解噪声注入功能对结果的影响

广告数据中心通过注入噪声来降低信息披露风险(即他人有可能可以了解到具体用户的信息),从而在隐私保护与实用性之间取得平衡。

广告数据中心内的噪声注入功能会按如下所述转换查询结果:

  • 对离群用户在汇总结果中所占的数据量限制取值范围,即汇总每位用户在每项汇总作业中所占的数据量,然后为每位用户所占的数据量设定取值范围的上下限。
  • 汇总已限制取值范围的每位用户所占的数据量。
  • 在每项汇总结果(每行中每次汇总函数调用的结果)中添加噪声。该随机噪声的规模与限制取值范围的上下限成正比。
  • 它会计算每行采用噪声的用户数,并去除用户数过少的行。这类似于差异检查模式下的 k-匿名性,但由于存在噪声,在同一数据集上运行的作业可能会删除不同的行。此外,噪声模式下的汇总要求较低(大约 20 列,而不是整整 50 列),因此删除的行数较少。

最终结果是一个数据集,其中每行的汇总结果都采用了噪声,并且去除了规模较小的组。这样做可掩盖单个用户对返回结果的影响。

关于汇总取值范围限制

广告数据中心内的噪声注入功能采用隐式或显式汇总取值范围限制,以限制离群用户所占的数据量。您可以根据自己的使用情形,选择使用何种类型的取值范围限制。

隐式取值范围限制

如果采用隐式取值范围限制,系统会自动确定上下限。您无需使用任何特殊的 SQL 语法,即可采用隐式取值范围限制。如果某一行的取值范围大于另一行,则隐式取值范围限制会为这些行指定不同的上下限。这样做通常会缩小每项结果的误差范围。另一方面,每项汇总作业会获得不同的取值范围上下限和噪声量,这可能会使它们难以比较。

如果在执行汇总作业时,数据的来源用户数量过少(例如使用罕见的条件调用 COUNTIF()),则隐式取值范围限制可能会失败。在这些情况下,系统会返回 NULL 结果。另请注意,COUNT(DISTINCT user_id) 会自动使用显式取值范围限制,其中上下限介于 01 之间。

显式取值范围限制

显式取值范围限制会将每位用户所占的总数据量限制在指定范围内。显式上下限会统一应用到所有行,且必须为字面量值。即使某些行中每位用户所占数据量的限制范围比其他行要更加广泛,系统也会针对所有行应用一致的上下限。这样一来,不同行的结果会更具有可比性,但某些行的噪声量可能会比采用隐式取值范围限制时更多。

对于任何一组给定的取值范围上下限而言,显式取值范围限制使用的噪声量都只有隐式取值范围限制的一半。因此,如果您可以估算出合理的上下限,那么以显式方式进行设置会得出更准确的结果。

若要使用显式取值范围限制,请为每个支持的汇总函数设定上下限。为此,分别添加一个整数来代表下限和上限即可。例如:

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. 查看已添加的噪声
  6. 可选:调整查询,以降低噪声带来的影响。

查看噪声带来的影响

成功完成查询后,广告数据中心会根据输出结果中有多少单元格具有预期数量的噪声来显示结果的可靠性。如果添加的噪声量超过单元格内所显示结果的 5%,则表示结果表中的值受到重大影响。请参阅下表中的影响范围。

对于受到影响的输出数据集,“详细信息”标签页会按照影响程度由高到低的顺序,列出噪声量最多的前 10 个列及它们各自在噪声中的占比。下面详细列出了噪声量符合预期的情况。

噪声量符合预期的数据 指示器颜色 影响程度
>95% 绿色 影响较小
85%-95% 黄色 影响适中
75%-85% 橙色 影响较大
<75% 红色 影响极大

如需详细了解噪声带来的影响,请执行以下操作:

  1. 点击报告
  2. 从列表中选择报告。隐私摘要提示会显示噪声量符合预期(对应的噪声添加量超出结果的 5%)的结果所占的百分比。
  3. 如需了解详情,请依次点击作业 > 详情
  4. 在作业详情中,查看隐私权消息。结果属于列出的某个类别。
  5. 如有需要,请调整查询以提高结果的准确度。

调整查询

如果只有少数用户对结果产生影响,则汇总结果更有可能包含不符合预期的噪声量。当行包含的用户数较少或部分用户未对结果产生影响(例如当使用 COUNTIF 函数时)时,就会出现上述情况。建议您根据噪声详情调整查询,提高噪声量符合预期的数据所占的百分比。

一般准则如下:

  • 扩大日期范围。
  • 重写查询以降低数据的精细程度,例如减少作为分组依据的参数或将 COUNTIF 替换为 COUNT
  • 移除添加噪声的列。
  • 使用显式取值范围限制

支持的汇总函数

系统支持搭配噪声使用以下汇总函数:

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

DISTINCT 关键字的使用条件有两个,一是必须与 COUNT 函数搭配使用;二是直接引用广告数据中心表中的 user_id 列,或是会返回 user_idNULL 的表达式(例如 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

关于整数结果

尽管广告数据中心会自动为这些汇总函数注入噪声,但函数签名不会改变。由于 INT64COUNTSUM 等函数会返回 INT64,因此注入噪声的结果中的所有小数部分都会被四舍五入。相对于结果和噪声的规模,这一点通常可以忽略不计。

如果您需要结果精确到小数部分,则应避免编写会返回 INT64 的函数,例如使用 SUM 并将其输入值转换为 FLOAT64


支持的查询句式

重要提示:广告数据中心提供的大多数标准最佳实践,仍然适用于使用噪声注入功能的查询。我们尤其建议您查看有关重复查询相同数据的指南。

本部分介绍了在使用噪声注入功能运行查询时支持的查询句式。

用户级汇总

我们采用与使用差异检查模式时相同的方式来支持不受限制的用户级汇总,并且只会在合并多位用户数据的汇总作业中注入噪声。明确按 user_id 分组的汇总作业(即按 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;

并行汇总

每项跨用户汇总作业都会各自接收噪声。您可以在单个语句中运行多个此类汇总作业,使用 JOINUNION 将结果合并到一个表中。

例如:

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)

请注意,尽管这种做法受支持,但在差异检查模式下应避免。这种做法在噪声方面不存在任何问题,因为每项并行汇总作业会各自添加噪声并进行过滤。

汇总数据与未汇总的数据相联接

由于广告数据中心仅支持按 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)


不受支持的查询句式

本部分介绍了在使用噪声注入功能运行查询时不受支持的查询句式。

包含今天在内的查询

噪声模式查询不支持查询当日数据。(不建议在差异检查模式下采取这种做法。)如果查询使用噪声注入功能,则无法选择当天的日期。

重复结果

在噪声模式下,广告数据中心会限制可重复执行相同汇总作业的频率。如果达到这些限制,您的噪声模式查询将无法访问数据集中经常查询的日期。以下是导致出现上述情况的原因示例。

查询重复是指以相同参数或高度相似的参数多次运行相同查询,例如日期范围重叠的情况。为避免出现此问题,请使用已导出到 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

在这种情况下,您应该移除其中一项重复的查询。

请注意,即使汇总在语法上有所不同,但只要计算的值相同,也会被视为重复。换句话说,如果具有一些 key 值的所有用户的 condition1condition2 都相同,则以下查询可能会重复:

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

如果您为某些用户群组设定的条件非常相似,不妨考虑将查询改为只有一个 COUNT

行重复是指广告数据中心表与 BigQuery 表联接,使得广告数据中心表中的每行与 BigQuery 表中的多个行一致。例如,如果 bq_table 中有多个行具有相同的广告系列 ID,则下列查询会产生重复:

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

在这种情况下,您应重新调整查询的结构,使 bq_table 的每个联接键值(在本示例中为 campaign_id)只有一行。

请注意,如果解除广告数据中心表中数组的嵌套,而大多数用户具有相同的值数组,则可能会产生相同的影响:

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。您可以重写查询来重新汇总添加噪声的汇总,但最终的汇总可能包含更多噪声。

如果无法避免,可以重写查询,改为直接从第一层导出结果。若要在不改变脚本结果的情况下在单个作业中完成此操作,您可以使用 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

在噪声模式下执行查询时,不得将单个用户的数据合并到一行中,除非是执行采用噪声的汇总。因此,若要显式连接 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))。

请注意,此限制仅适用于广告数据中心表(维度表除外)之间的联接,但不适用于由客户拥有的表。例如,我们允许:

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

广告数据中心与 BigQuery 之间的并集

采用噪声的汇总需要具有用户标识符才能正常运行。在 BigQuery 中,由客户拥有的数据没有用户标识符,因此必须先联接到广告数据中心,然后才能与采用噪声的汇总建立并集。

此查询会导致验证错误:

SELECT COUNT(*) FROM (
  SELECT 1 FROM adh.google_ads_impressions
  UNION ALL
  SELECT 1 FROM bigquery_project.dataset.table
)

若要解决此问题,您应该联接 BigQuery 表以扩充广告数据中心的数据,而不是在上述两者之间建立并集;或者,您也可以拆分数据,以单独汇总每个来源。

请注意,您可以在多个包含用户数据的广告数据中心表或多个由客户拥有的 BigQuery 表之间建立并集,但无法将两者混合。

在广告数据中心与 BigQuery 之间正确建立联接

如果与由客户拥有的数据建立外部联接,可能会导致行缺少用户标识符,进而导致噪声无法正常运行。

这两项查询都允许广告数据中心端存在缺失用户标识符的未匹配行,因此会导致验证错误:

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

请注意,总数会单独添加噪声,而总值可能不会累加,但总数通常比添加噪声的行的总和更加准确。

跨模式创建的表

广告数据中心内未导出的表,只能与其创建时采用的相同隐私模式搭配使用。您不能在常规汇总模式下创建表,然后在噪声模式下使用该表,反之亦然(除非先将该表导出到 BigQuery)。