Injeção de ruído

Injeção de ruído é uma técnica usada para proteger a privacidade do usuário ao consultar um banco de dados. Ela adiciona um ruído aleatório à cláusula SELECT de agregação de uma consulta. Esse ruído protege a privacidade do usuário e fornece resultados razoavelmente precisos com um limite mínimo de agregação necessário para a saída. A maioria das consultas atuais pode ser executada no modo de ruído, com algumas limitações.

Benefícios de usar a injeção de ruído

A solução de problemas ficou mais simples: as linhas só são omitidas devido aos requisitos de agregação, facilitando a solução de problemas e a adaptação das consultas.

Não é necessário aprender uma nova sintaxe:você não precisa fazer isso nem conhecer os conceitos de privacidade para usar o ruído.

A precisão dos resultados é informada:um job concluído mostra a porcentagem total de dados que podem ter sido afetados por ruído.

Como o ruído afeta as normas de privacidade

Requisito de agregação: a injeção de ruído gera dados de impressão representados por aproximadamente 20 ou mais usuário únicos, além de dados de conversão ou cliques representados por aproximadamente 10 ou mais usuários únicos.

Verificações estáticas: não há impacto.

Orçamentos e limites de consulta:a injeção de ruído impõe limites ao número de vezes que a mesma consulta pode ser executada no mesmo conjunto de dados. Ao recalcular os mesmos resultados agregados em uma única consulta ou em várias execuções de consulta, seus resultados podem ser bloqueados. Isso pode acontecer se você executar consultas em janelas deslizantes ou fizer a mesma solicitação diversas vezes. Para mais informações, consulte Resultados repetidos.

Saiba mais sobre as verificações de privacidade.

Como a injeção de ruído afeta os resultados

O Ads Data Hub injeta ruído para reduzir o risco de divulgação, ou seja, o risco de alguém ter acesso a informações sobre um usuário individual. Ele busca o equilíbrio entre a privacidade e a utilidade.

A injeção de ruído no Ads Data Hub transforma a consulta da seguinte maneira:

  • Ela restringe as contribuições de usuários outliers nos resultados agregados. Ela soma a contribuição dos usuários em cada agregação e depois impõe limites de restrição mínimos e máximos às contribuições.
  • Ela agrega as contribuições restringidas de cada usuário.
  • Ela adiciona ruído a cada resultado agregado, ou seja, o resultado das chamadas de função de agregação em cada linha. A escala desse ruído aleatório é proporcional aos limites de restrição.
  • Ela calcula uma quantidade de usuários com ruído para cada linha e elimina aquelas com poucas pessoas (aproximadamente 20 usuários por linha). Devido ao ruído, os jobs executados no mesmo conjunto de dados podem descartar linhas diferentes. Esse requisito pode ser evitado usando grupos públicos.

O resultado final é um conjunto de dados em que cada linha tem resultados agregados com ruído e pequenos grupos foram eliminados. Isso mascara o efeito de um usuário individual sobre os resultados retornados.

Sobre a restrição de agregação

A injeção de ruído no Ads Data Hub usa restrição de agregação implícita ou explícita para limitar a contribuição de outliers. Você pode escolher que tipo de restrição usar, dependendo do seu caso de uso.

Restrição implícita

Você não precisa de nenhuma sintaxe de SQL especial para usar a fixação implícita, que é aplicada por padrão. Os limites implícitos são derivados dos próprios dados e determinados para cada agregação. Se algumas agregações tiverem um intervalo de valores maior do que outras, a restrição implícita poderá inferir limites diferentes para diferentes agregações, conforme apropriado. Isso geralmente resulta em menos erros. O COUNT(DISTINCT user_id) limita automaticamente a contribuição por usuário a 1.

Restrição explícita

A restrição explícita limita a contribuição total de cada usuário para um conjunto específico. As restrições explícitas são aplicadas de maneira uniforme a todas as agregações e precisam ser valores literais. O bloqueio explícito pode fornecer resultados melhores quando os limites são geralmente conhecidos. Por exemplo, idades delimitadoras entre 0 e 100 refletem as informações públicas, porque a idade da maioria das pessoas geralmente está dentro desse intervalo.

O Ads Data Hub oferece ADH.ANONfunções de agregação complementares para restrição explícita. Para usar a restrição explícita, defina os limites para cada função agregada compatível adicionando números inteiros que representem o limite menor e o limite maior. Exemplo:

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

Como executar uma consulta usando a injeção de ruído

  1. Abra um relatório.
  2. Clique no botão Configurações de ruído de privacidade e alterne para a posição Usar ruído.
  3. Execute a consulta.
  4. Analise o impacto do ruído adicionado.
  5. Opcional: adapte a consulta para reduzir o impacto do ruído.

Como analisar o impacto do ruído

Quando um job é concluído, o Ads Data Hub mostra a confiabilidade do resultado no resumo de privacidade. A confiabilidade é baseada na porcentagem de células na saída que podem ser muito afetadas por ruído. Um valor na tabela de resultados é considerado afetado se o ruído adicionado for maior do que 5% do resultado na célula.

Para os conjuntos de dados de saída afetados, o resumo de privacidade lista as 10 colunas com mais ruído, do maior impacto para o menor, e sua respectiva contribuição para o ruído. Este é o detalhamento dos rótulos de impacto de ruído.

% de resultados afetados Cor indicadora Impacto
Menos de 5% Verde Baixo impacto
5% a 15% Amarelo Médio impacto
15% a 25% Orange Alto impacto
Mais de 25% Vermelho Altíssimo impacto

Você também pode conferir uma prévia do resumo de privacidade dos jobs de relatório recentes na página Início. Para conferir a privacidade de um job específico, passe o cursor sobre o ícone de dica de privacidade privacy_tip no card do job em Atividade recente.

Adaptação das consultas

As agregações têm mais probabilidade de serem afetadas por ruído quando poucos usuários contribuem para o resultado. Isso pode acontecer quando as agregações são calculadas com base em pequenos conjuntos de usuários ou quando alguns usuários não afetam os resultados, o que pode acontecer, por exemplo, com a função COUNTIF. Com base no relatório de ruído, você pode ajustar a consulta para reduzir a porcentagem de resultados afetados.

Estas são as orientações gerais:

  • Aumente o período.
  • Reescreva a consulta para reduzir a granularidade dos dados (por exemplo, usando menos parâmetros para agrupar ou substituindo COUNTIF por COUNT).
  • Remova as colunas com ruído.
  • Tente o bloqueio explícito quando for possível escolher limites razoáveis.

Funções de agregação compatíveis

As funções de agregação a seguir são compatíveis com ruído:

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

A palavra-chave DISTINCT só é compatível com a função COUNT. Quando usadas com uma referência direta à coluna user_id de uma tabela do Ads Data Hub ou uma expressão que retorna user_id ou NULL, como COUNT(DISTINCT IF(..., user_id, NULL)), as funções COUNT DISTINCT e APPROX_COUNT_DISTINCT(...) são calculadas fixando a contribuição por usuário em 1. Quando COUNT DISTINCT faz referência a uma coluna que não é user_id, ela é aproximada usando APPROX_COUNT_DISTINCT com restrição implícita.

Funções de agregação complementares

Além de oferecer suporte a agregadores regulares, o Ads Data Hub apresenta funções de agregação ADH.ANON complementares que oferecem suporte ao bloqueio explícito. Esses agregadores compartilham a sintaxe com as funções de agregação de privacidade diferencial do BigQuery, mas não exigem a cláusula 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 ] )

Parâmetros ADH.ANON_SUM, ADH.ANON_COUNT e ADH.ANON_AVG:

  • contribution_bounds_per_group: as contribuições por usuário são ajustadas para cada partição definida pelas chaves GROUP BY. Os limites superior e inferior são aplicados aos valores por grupo após a agregação dos valores por usuário.
  • lower_bound: literal numérico que representa o menor valor a ser incluído em uma agregação.
  • upper_bound: literal numérico que representa o maior valor a ser incluído em uma agregação.

Parâmetros ADH.ANON_PERCENTILE_CONT:

  • percentile: o percentil a ser calculado, um literal no intervalo [0, 1].
  • contribution_bounds_per_row: as contribuições por usuário são ajustadas por linha (por registro). Os limites de restrição explícitos são necessários para o percentil e, portanto, só são compatíveis como uma função complementar.
  • lower_bound: literal numérico que representa o menor valor a ser incluído em uma agregação.
  • upper_bound: literal numérico que representa o maior valor a ser incluído em uma agregação.

Parâmetros ADH.ANON_COUNT_DISTINCT:

  • max_contributions_per_group: as contribuições por usuário são ajustadas para cada partição definida pelas chaves GROUP BY. O limite superior restringe a contribuição máxima do usuário por grupo após a agregação dos valores por usuário.
  • upper_bound: literal numérico que representa o maior valor a ser incluído em uma agregação.

Calcular MIN e MAX

As funções MIN e MAX não são compatíveis diretamente com agregações de ruído, mas geralmente há métodos alternativos para calcular esses resultados.

Se você tiver um MIN ou MAX de valores que podem ser usados como chaves de agrupamento, como data do evento, primeiro AGRUPE POR esse valor e depois calcule MIN/MAX. Isso retorna o valor mínimo ou máximo que passa pelo limite de agregação.

Exemplo:

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)

Como alternativa, se você tiver um MIN ou MAX de valores granulares com limites conhecidos, use PERCENTILE_CONT com limites explícitos para um resultado aproximado.

Exemplo:

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

Sobre resultados com números inteiros

Embora o Ads Data Hub injete ruído para as funções de agregação de maneira automática, as assinaturas das funções não mudam. Como funções do tipo COUNT ou SUM de INT64 retornam INT64, qualquer parte decimal do resultado com ruído é arredondada. Isso geralmente é ignorado devido ao tamanho do resultado e do ruído.

Se você precisar da granularidade da casa decimal no seu resultado, evite escrever funções que retornem INT64 (por exemplo, usando SUM com entrada convertida para FLOAT64).

Sobre resultados negativos

Em princípio, ruídos com valores muito pequenos podem resultar em números negativos, mesmo quando isso deveria ser semanticamente impossível para a consulta. Para manter o comportamento esperado, todas as formas de COUNT e COUNTIF são automaticamente fixadas em zero, para que nunca gerem resultados negativos. Se você quiser o mesmo comportamento com outra função, como SUM, poderá fixar os resultados manualmente usando GREATEST(0, SUM(...)).

Essa mudança geralmente é insignificante, mas introduz um pequeno viés positivo nos resultados gerais.

Grupos públicos

Com uma cláusula GROUP BY, os resultados anonimizados de uma consulta são agregados em grupos. O uso de um limite de agregação garante que um número suficiente de usuários esteja presente no grupo para que os dados individuais sejam protegidos. O processo de determinar quais grupos podem ser lançados é chamado de "seleção de partição".

Em muitos casos, os grupos são de conhecimento público. Por exemplo, o agrupamento por versão do navegador, dia da semana ou região geográfica não depende dos dados do usuário se os valores da chave de agrupamento forem conhecidos com antecedência. Nesse caso, a seleção de partição pode ser omitida, já que a presença ou ausência de um grupo na saída não fornece novas informações sobre os usuários.

O Ads Data Hub identifica as consultas qualificadas para grupos públicos e não aplica limites de agregação a elas. Isso significa que nenhuma linha de saída é filtrada. Os resultados calculados com base em um pequeno número de usuários podem ser muito afetados por ruídos.

Para se qualificar para grupos públicos, a consulta precisa ser estruturada de forma que todas as chaves de agrupamento sejam conhecidas com antecedência. As colunas de agrupamento precisam atender a estas condições:

  • Elas vêm de uma tabela pública (uma tabela ou cláusula SELECT sem dados de usuários do Ads Data Hub).
  • Elas têm SELECT DISTINCT aplicado para impor valores exclusivos.
  • Elas são unidas à consulta com um OUTER JOIN em todas as colunas individuais.

Quando uma consulta se qualifica para grupos públicos, a interface do Ads Data Hub mostra a seguinte mensagem de validação: "A junção é compatível com grupos públicos e não está sujeita a limites de agregação".

Exemplos de consultas de grupos públicos:

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

No primeiro exemplo, o adh.google_ads_impressions table protegido é unido à tabela adh.age_group, que não contém dados do usuário na coluna age_group_id. A mesma coluna age_group_id da tabela pública aparece na cláusula GROUP BY.

Da mesma forma, no segundo exemplo, a tabela protegida adh.google_ads_impressions é unida à tabela pública, que é fornecida explicitamente como UNNEST([1, 2, 3]). Nos dois exemplos, a chave de agrupamento age_group_id vem da tabela pública.

Também é possível fornecer vários itens de agrupamento, por exemplo:

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;

Para estruturar corretamente a RIGHT OUTER JOIN com uma subconsulta que define os grupos públicos, verifique se a instrução SELECT DISTINCT na subconsulta inclui apenas os campos usados na cláusula ON da JOIN. Esses mesmos campos também precisam estar presentes na cláusula GROUP BY da consulta principal. Por exemplo, a consulta a seguir não se qualifica para grupos públicos:

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

A ausência de filtragem nas consultas de grupos públicos pode ser benéfica para consultas executadas recorrentemente, já que a saída é sempre retornada para os mesmos valores fixos de chaves de agrupamento. Isso pode ser muito útil, por exemplo, para criar painéis periódicos.

Uma observação: se uma tabela pública fornecer um grande número de valores de chave de agrupamento, você poderá receber muitas linhas com poucos ou nenhum dado, e todas elas serão informadas como tendo alto impacto de ruído. Nesse caso, considere fornecer explicitamente uma lista menor de chaves com apenas os valores de seu interesse.

GROUP BY ROLLUP

GROUP BY ROLLUP estende a cláusula GROUP BY para incluir outras linhas que representam subtotais e totais gerais com base na hierarquia definida na lista de agrupamento. No Ads Data Hub, GROUP BY ROLLUP só está disponível quando a injeção de ruído é usada. A sintaxe segue a especificação padrão do BigQuery.

Totais consistentes com grupos públicos

Quando a injeção de ruído é usada, o ruído é aplicado de forma independente em cada nível de agregação. Isso significa que os totais não têm necessariamente consistência perfeita, então os subtotais não somam os totais gerais. Por exemplo, a soma das contagens de cidades pode não corresponder ao total da região.

Ao usar GROUP BY ROLLUP em combinação com grupos públicos, o Ads Data Hub elimina essa inconsistência nos resultados. Isso é possível porque nenhum resultado é filtrado devido à definição de limites. Por exemplo, a contagem de cidades vai somar a contagem da região correspondente. Observação: para resultados inteiros, pequenas diferenças devido a erros de arredondamento de ponto flutuante são possíveis.

Benefícios de usar grupos públicos com ROLLUP

  1. Agregações consistentes: garante que subtotais e totais gerais estejam alinhados.
  2. Maior precisão: o processo de consistência aumenta a precisão geral dos dados. Níveis mais altos na hierarquia de rollup (como agregações no nível do país) se baseiam em conjuntos de dados maiores e tendem a ter um impacto de ruído relativo menor. Essas informações mais estáveis de níveis mais altos são usadas para ajustar e melhorar a qualidade dos níveis mais ruidosos e granulares (como agregações no nível da cidade).

É altamente recomendável usar GROUP BY ROLLUP com grupos públicos sempre que possível para aproveitar essas vantagens.

Exemplos de ROLLUP com grupos públicos:

ROLLUP com uma única chave:

Usando uma tabela:

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);

Usar uma lista inline:

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);

Resultado de amostra:

country_code count
CN 6155
CA 16439
EUA 256695
MX 10780
null 290067

A linha com NULL para country_code representa o total geral. A soma das contagens de cada país, 290.069, é muito próxima da linha do total geral, 290.067. A pequena diferença é resultado do arredondamento.

ROLLUP com várias chaves de agrupamento:

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);

Resultado de amostra:

campaign_id browser count observações
1 Chrome
1 Outro
2 Chrome
2 Outro
1 null Subtotal for campaign_id = 1
2 null Subtotal for campaign_id = 2
null null Total geral

ROLLUP com conjuntos de itens agrupáveis:

Para tratar várias colunas como uma única unidade na hierarquia de rollup, coloque-as entre parênteses, por exemplo: ROLLUP ((column1, column2), column3). Isso é resumido pelo par (campaign_id, browser) como uma única entidade.

O GROUP BY ROLLUP ((campaign_id, browser)) vai gerar subtotais para:

  • (campaign_id, browser): mais granular
  • (): total geral

Ela não vai criar subtotais intermediários apenas para (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));

Resultado de amostra:

campaign_id browser count observações
1 Chrome
1 Outro
2 Chrome
2 Outro
null null Total geral

Observação: usar ROLLUP com muitos níveis hierárquicos ou um grande número de valores distintos nas chaves de agrupamento pode gerar muitas linhas de saída. Isso pode causar erros devido aos limites do Ads Data Hub em resultados repetidos. Recomendamos manter o número de níveis hierárquicos e a cardinalidade das chaves de agrupamento relativamente pequenos.


Padrões de consulta compatíveis

Importante: a maioria das práticas recomendadas padrão do Ads Data Hub ainda se aplica a consultas que usam injeção de ruído. Em particular, recomendamos que você leia as orientações sobre consultas repetidas dos mesmos dados.

Esta seção descreve os padrões compatíveis ao executar consultas usando a injeção de ruído.

Dados agregados no nível do usuário

O ruído só é injetado em agregações que combinam dados de vários usuários. Agregações que agrupam ou particionam explicitamente por user_id não recebem ruído nem restringem o uso de funções. Agregações no nível do usuário que não fazem agrupamentos explícitos por user_id, como GROUP BY impression_id, são tratadas como agregações de usuários diferentes. Por isso, o ruído é adicionado.

Agrupar usando external_cookie não é suficiente. Embora o external_cookie possa ser usado para juntar *_tabelas de correspondência com tabelas do cliente, todas as agregações devem agrupar os dados explicitamente com base nas colunas user_id e coluna external_cookie.

Exemplo de função agregada:

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;

Exemplo de função analítica:

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;

Dados agregados paralelos

Cada agregação de usuários diferentes recebe ruído de maneira independente. Você pode executar várias dessas agregações em uma única instrução, combinando resultados em uma tabela usando JOIN ou UNION.

Exemplo:

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)

Dados agregados mesclados com dados não agregados

Como o Ads Data Hub só é compatível com janelas analíticas que fazem particionamento por user_id, uma solução comum é agregar esses resultados de modo separado e fazer a mesclagem automática deles antes de agregá-los de novo.

Exemplo:

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

No modo de ruído, é desaconselhável reagregar os resultados agregados, como AVG(campaign_imps).


Padrões de consulta não compatíveis

Esta seção descreve padrões não compatíveis ao executar consultas usando injeção de ruído.

Resultados repetidos

No modo de ruído, o Ads Data Hub limita a frequência com que você pode repetir a mesma agregação. Se você atingir os limites, suas consultas do modo de ruído vão perder acesso às datas das consultas frequentes no conjunto de dados. Confira a seguir exemplos de como isso pode ocorrer.

A repetição de consulta acontece quando a mesma consulta é executada várias vezes com os mesmos parâmetros, incluindo períodos que se sobrepõem. Você pode evitar isso usando os dados que já foram exportados para seu projeto do BigQuery.

Se dois jobs consultarem períodos sobrepostos, eles podem produzir repetições se realizarem o mesmo cálculo nos mesmos usuários. Por exemplo, a consulta a seguir, executada em períodos sobrepostos, cria repetições porque está particionando por data:

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

Nesse caso, você precisa executar a consulta em segmentos de data separados.

Outro exemplo de repetição acontece quando os dados de alguma maneira independem de data. A consulta a seguir produz repetições quando executada em datas sobrepostas, em que os dois jobs abrangem todo o ciclo de vida de uma campanha:

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

Nesse caso, você precisa executar a consulta apenas uma vez, porque o resultado não muda.

A repetição de agregação acontece quando a mesma agregação é repetida várias vezes em uma consulta:

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

Nesse caso, você precisa remover uma das repetições.

Mesmo que as agregações sejam sintaticamente diferentes, mas calculem o mesmo valor, ele seria contado como uma repetição. Em outras palavras, se os valores de condition1 e condition2 forem os mesmos para todos os usuários com algum valor de key, a consulta a seguir teria uma repetição:

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

Se você tiver condições que sejam bastante semelhantes para alguns grupos de usuários, reescreva a consulta para ter apenas um COUNT.

A duplicação de linhas acontece quando uma tabela do Ads Data Hub é mesclada com uma tabela do BigQuery de uma maneira que cada linha da tabela do Ads Data Hub corresponde a várias linhas da tabela do BigQuery. Por exemplo, a consulta a seguir produz uma repetição se houver várias linhas com o mesmo ID de campanha em bq_table:

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

Nesse caso, você precisa reestruturar a consulta para que bq_table tenha apenas uma linha por chave-valor de junção (campaign_id, nesse caso).

Desaninhar uma matriz da tabela do Ads Data Hub pode produzir o mesmo efeito se a maioria dos usuários tiver as mesmas matrizes de valores:

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

Como regra geral, limite a computação dos mesmos resultados a 10 vezes ou menos. À medida que você se aproxima do limite, o Ads Data Hub mostra avisos. Se os mesmos resultados continuarem sendo calculados além do limite, seus jobs começarão a ser bloqueados com erros.

Conheça outras práticas recomendadas para consultas.

Sobre as janelas de lookback

Alguns padrões de consulta geram relatórios em um grande período, regenerando-se periodicamente para incluir novos resultados. Essas consultas podem precisar de ajustes para funcionar no modo de ruído, porque, se recalcularem resultados anteriores, serão bloqueadas. Em vez disso, cada job deve gerar apenas novos resultados, que podem ser combinados com os de jobs anteriores para um relatório completo.

Por exemplo, se você estiver criando um relatório de métricas por data, atualizado diariamente:

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

Não execute esse comando com um período muito longo, porque isso vai recalcular os resultados dos dias anteriores. Em vez disso, execute cada job apenas no dia mais recente, que tem novos dados, e combine com os resultados de jobs anteriores. Se você quiser coletar todos os resultados em uma única tabela em vários jobs, use uma instrução MERGE.

Você ainda pode recalcular os períodos anteriores para atualizar os resultados (por exemplo, para considerar dados que chegaram atrasados), mas evite recalcular um único resultado muitas vezes, conforme descrito anteriormente.

Reagregação direta

O ruído é aplicado à primeira camada da agregação de usuários diferentes na consulta. Consultas com várias camadas de agregação combinam resultados ruidosos, então os agregados finais podem ter muito mais ruído. Essas consultas recebem um aviso na validação:

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

Para receber os melhores resultados do ruído, calcule todas as operações de usuários diferentes em uma única agregação. Por exemplo, considere SUM de eventos em vez de SUM de contagens intermediárias.

Se a agregação de várias camadas for inevitável, exporte os resultados diretamente da primeira camada para resolver o aviso. Para fazer isso em um único job sem mudar os resultados de script, crie uma tabela temporária (ou uma tabela exportada para seu projeto do BigQuery) com a sintaxe OPTIONS(privacy_checked_export=true). Exemplo:

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

Saiba mais sobre tabelas temporárias.

Se a primeira camada de agregação for muito granular para verificações de privacidade, considere reescrever a consulta com agregações no nível do usuário. Se isso não for possível, não haverá suporte para essa consulta no modo de ruído.

IDs de usuários não mesclados

Consultas no modo de ruído não devem combinar dados de usuários separados em uma única linha, exceto ao realizar uma agregação com ruído. Como consequência, as mesclagens de dados do Ads Data Hub não agregados devem ser explicitamente mescladas na coluna user_id.

Esta consulta não é mesclada de maneira explícita na coluna user_id, o que resulta em um aviso de validação:

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

Junções como essa podem não funcionar como esperado porque apenas linhas com o mesmo valor de user_id vão corresponder. Isso pode ser corrigido ajustando a cláusula USING para incluir explicitamente user_id. Por exemplo, USING(impression_id, user_id).

Essa limitação se aplica somente a mesclagens entre tabelas do Ads Data Hub (com exceção das tabelas de dimensões). Isso não se aplica às tabelas do cliente. Por exemplo, o seguinte é permitido:

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

Mesclagens direitas do Ads Data Hub com o BigQuery

Mesclagens externas com dados de propriedade do cliente podem resultar em linhas sem identificadores de usuários, o que impede o ruído de funcionar bem.

Estas duas consultas resultam em avisos de validação porque permitem linhas não correspondentes sem identificadores de usuários no 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)

Qualquer mesclagem funcionaria se a ordem das tabelas fosse invertida. Há também uma exceção para tabelas de RDID que fazem junção diretamente no device_id_md5. Por exemplo, a consulta a seguir vai funcionar sem avisos:

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

Resumo das linhas filtradas

As especificações do resumo das linhas filtradas não são compatíveis com o modo de ruído. Esse recurso costuma ser desnecessário com o ruído devido às baixas taxas de filtragem e à falta de filtragem das verificações de diferenças.

Se você notar uma filtragem significativa de dados em um resultado de ruído, aumente os dados agregados. É possível realizar uma agregação paralela no conjunto completo de dados para comparar uma estimativa do total usando ROLLUP ou uma agregação separada. Por exemplo:

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

A contagem total recebe ruído de maneira independente e os valores totais podem não ser relevantes, mas a contagem total geralmente é mais precisa do que somar as linhas com ruído.

Tabelas criadas com vários modos

Tabelas não exportadas no Ads Data Hub só podem ser usadas com o mesmo modo de privacidade em que foram criadas. Não é possível criar uma tabela no modo de agregação normal e usá-la no modo de ruído ou vice-versa (a menos que a tabela seja exportada para o BigQuery primeiro).