Detecção de fraude com o BigQuery Graph

1. Introdução

Cabeçalho de marketing: fraude em fintechs

A atividade fraudulenta geralmente envolve redes ocultas de entidades conectadas, por exemplo, várias contas que compartilham o mesmo endereço de e-mail, número de telefone ou endereço físico. Os bancos de dados relacionais tradicionais podem ter dificuldades para consultar essas relações complexas e de vários saltos de maneira eficiente.

O BigQuery Graph permite analisar essas redes em escala usando bancos de dados de gráficos. É possível definir um gráfico de propriedades nas tabelas do BigQuery e usar a linguagem GraphQL (GQL) para encontrar padrões nos dados.

Uma aplicação comum de redes de gráficos para detecção de fraudes é interromper pedidos que têm um endereço de entrega associado a uma rede de fraudes ou pagamentos pertencentes a .

Neste codelab, você vai criar uma solução de detecção de fraudes usando o BigQuery Graph. Você vai carregar dados do Cloud Storage, criar um gráfico de propriedades e usar consultas de gráficos para identificar conexões suspeitas.

O que você vai aprender

  • Como criar um conjunto de dados do BigQuery e carregar dados.
  • Como definir um gráfico de propriedades usando DDL.
  • Como consultar o gráfico usando GQL.
  • Como usar a análise de gráficos para detectar fraudes.

O que é necessário

  • Ter um projeto do Google Cloud com o faturamento ativado.
  • Um ambiente de notebook do BigQuery (BigQuery Studio ou Colab Enterprise).

Custo

Este laboratório usa recursos faturáveis do Google Cloud. O custo estimado é de menos de US $5, supondo que você exclua os recursos após a conclusão.

2. Antes de começar

Selecionar ou criar um projeto do Google Cloud

  1. No Console do Google Cloud, na página de seletor de projetos, selecione ou crie um projeto na nuvem do Google Cloud.
  2. Verifique se a cobrança está ativada para o seu projeto do Google Cloud. Saiba como verificar se o faturamento está ativado.

Escolher seu ambiente

Você vai precisar de um ambiente de notebook para executar este laboratório. É possível usar o BigQuery Studio ou o Colab Enterprise.

  1. Acesse a página do BigQuery no Console do Google Cloud.
  2. Você vai usar o notebook Python para executar as consultas de gráficos.

Iniciar o Cloud Shell

  1. Clique em Ativar o Cloud Shell na parte de cima do console do Google Cloud.
  2. Verificar a autenticação:
gcloud auth list
  1. Confirmar seu projeto:
gcloud config get project
  1. Defina, se necessário:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID

Ativar APIs

Execute este comando para ativar a API BigQuery necessária:

gcloud services enable bigquery.googleapis.com

3. Carregar dados

Nesta etapa, você vai criar um conjunto de dados do BigQuery e carregar os dados de amostra do Cloud Storage.

Os dados de amostra consistem em vários arquivos CSV que representam um ambiente de varejo simulado:

  • customers.csv: informações da conta do cliente.
  • emails.csv: endereços de e-mail.
  • phones.csv: números de telefone.
  • addresses.csv: endereços físicos.
  • customer_emails.csv, customer_phones.csv, customer_addresses.csv: tabelas de vinculação.
  • orders.csv: histórico de pedidos, incluindo indicadores de fraude.

#create_the_data_set

Crie um conjunto de dados chamado fraud_demo para armazenar as tabelas.

  1. Para este codelab, vamos executar comandos SQL. É possível executar esses comandos no BigQuery Studio > Editor de SQL ou usar o bq query comando no Cloud Shell. Nova consulta SQLVamos presumir que você está usando o Editor de SQL do BigQuery para uma melhor experiência com instruções de criação de várias linhas.
CREATE SCHEMA IF NOT EXISTS `fraud_demo` OPTIONS(location="US");

Carregar tabelas

Execute as instruções SQL a seguir para carregar dados do Cloud Storage no conjunto de dados.

LOAD DATA OVERWRITE `fraud_demo.customers`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customers.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.emails`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/emails.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.phones`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/phones.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.addresses`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/addresses.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_emails`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_emails.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_phones`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_phones.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_addresses`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_addresses.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.orders`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/orders.csv'],
  skip_leading_rows = 1
);

4. Criar o gráfico de propriedades

Agora que os dados estão carregados, você pode definir o gráfico de propriedades. Um gráfico de propriedades consiste em nós (entidades) e arestas (relações).

Neste laboratório, os nós são:

  • Cliente: representa o titular da conta.
  • Telefone: representa um número de telefone.
  • E-mail: representa um endereço de e-mail.
  • Endereço: representa um endereço físico.

As arestas são:

  • OwnsPhone: conecta um cliente a um telefone.
  • OwnsEmail: conecta um cliente a um e-mail.
  • LinkedToAddress: conecta um cliente a um endereço.

Criar o gráfico

Execute a instrução DDL a seguir para criar o gráfico chamado FraudDemo no conjunto de dados fraud_demo.

CREATE OR REPLACE PROPERTY GRAPH fraud_demo.FraudDemo
  NODE TABLES(
    fraud_demo.customers
      KEY(account_id)
      LABEL Customer PROPERTIES(
        account_id,
        name),

    fraud_demo.emails
      KEY(email)
      LABEL Email PROPERTIES(
        email,
        email_type),

    fraud_demo.phones
      KEY(phone_number)
      LABEL Phone PROPERTIES(
        phone_number,
        phone_type),

    fraud_demo.addresses
      KEY(address)
      LABEL Address PROPERTIES(
        address,
        address_type)
  )
  EDGE TABLES(
    fraud_demo.customer_emails
      KEY(account_id, email)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(email) REFERENCES emails(email)
      LABEL OwnsEmail PROPERTIES(
        account_id,
        email,
        last_updated_ts),

    fraud_demo.customer_phones
      KEY(account_id, phone_number)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(phone_number) REFERENCES phones(phone_number)
      LABEL OwnsPhone PROPERTIES(
        account_id,
        phone_number,
        last_updated_ts),

    fraud_demo.customer_addresses
      KEY(account_id, address)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(address) REFERENCES addresses(address)
      LABEL LinkedToAddress PROPERTIES(
        account_id,
        address,
        last_updated_ts)
  );

5. Analisar redes (2 saltos)

Abra Novo notebook no BigQuery Studio.

Criar notebook

Para as partes de visualização e recomendação deste codelab, vamos usar um notebook do Google Colab no BigQuery Studio. Isso nos permite visualizar facilmente os resultados do gráfico.

O notebook do BigQuery Graph é implementado como um IPython Magics. Ao adicionar o comando mágico %%bigquery com a função TO_JSON, é possível visualizar os resultados conforme mostrado nas seções a seguir. Nesta etapa, você vai executar uma consulta de gráfico para encontrar conexões simples entre contas. Essa é uma consulta de "2 saltos" porque ela percorre 2 saltos de um nó inicial para encontrar nós relacionados (por exemplo, cliente -> e-mail -> cliente).

Vamos começar investigando a conta pertencente a Nicole Wade. Queremos encontrar contas relacionadas a ela por dois saltos.

Executar a consulta de 2 saltos

Execute a consulta a seguir no notebook.

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH 
 p=(a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']- (n) ){2}
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Verify the final node in the hop array is a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(1)]))

RETURN TO_JSON(p) AS paths

Entender os resultados

Esta consulta:

  1. Começa no nó Customer com account_id "d2f1f992-d116-41b3-955b-6c76a3352657" (Nicole Wade).
  2. Segue qualquer uma das arestas OwnsEmail, OwnsPhone, ou LinkedToAddress para um nó de conexão (Phone, Email, ou Address).
  3. Segue as arestas de volta desse nó de conexão para outros nós Customer.
  4. Filtra as arestas com base em um carimbo de data/hora (last_updated_ts) para conferir o estado da rede em um momento específico.

Você vai notar que Zachary Cordova e Brenda Brown estão conectados a Nicole pelo mesmo endereço.

6. Analisar redes (4 saltos)

Nesta etapa, você vai estender a consulta para encontrar relações mais complexas. Vamos procurar conexões de 4 saltos. Isso nos permite encontrar contas conectadas por várias entidades intermediárias (por exemplo, cliente A -> e-mail -> cliente B -> telefone -> cliente C).

Também vamos observar como essa rede muda ao longo do tempo.

O estado "antes"

Primeiro, vamos analisar a rede como ela existia em 30 de julho de 2025.

Execute a seguinte consulta:

%%bigquery --graph
%%bigquery --graph

MATCH p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']- (n) ){3, 5}(reachable_a:Customer)
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Ensure the final node in the dynamic chain is actually a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(ARRAY_LENGTH(n) - 1)]))
GRAPH fraud_demo.FraudDemo
RETURN 
  TO_JSON(p) AS paths,                   -- Array of all traversed edges
  ARRAY_LENGTH(e) AS hop_count

O estado "depois"

Agora, vamos conferir como a rede fica duas semanas depois. Vamos executar a mesma consulta, mas sem as restrições de data.

Execute a seguinte consulta:

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress]- (n) ){3, 5}(reachable_a:Customer)
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Ensure the final node in the dynamic chain is actually a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(ARRAY_LENGTH(n) - 1)]))

RETURN 
  TO_JSON(p) AS paths,                   -- Array of all traversed edges
  ARRAY_LENGTH(e) AS hop_count

Entender os resultados

Ao remover os filtros de data, você está consultando o conjunto de dados completo. Você vai notar que a rede cresceu significativamente. Nicole Wade agora faz parte de um grupo muito maior e altamente conectado. Essa expansão rápida de uma rede conectada é um forte indicador de atividade potencialmente fraudulenta, como um grupo de fraudes que compartilha recursos ao longo do tempo.

7. Gerar relatório de fraude

Nesta etapa, você vai combinar a análise de grafos com dados da empresa (pedidos) para gerar um relatório de fraude abrangente. Você vai identificar contas em risco e possíveis pedidos fraudulentos.

Essa consulta é mais complexa. Ela usa GRAPH_TABLE para executar a consulta de gráfico no SQL padrão e calcula a mudança no tamanho da rede (diff) entre os estados "antes" e "depois" que observamos na etapa anterior.

Executar a consulta do relatório de fraude

Execute a consulta a seguir no notebook.

%%bigquery --graph
WITH num_orders AS (
  SELECT account_id, COUNT(1) AS num_order
  FROM fraud_demo.orders
  WHERE order_time > '2025-07-30'
  GROUP BY account_id
),

orders AS (
  SELECT account_id, order_id, fraud, order_total
  FROM fraud_demo.orders
  WHERE order_time > '2025-07-30'
),

-- Use Quantified Path Patterns to find connections up to 4 hops away
latest_connect AS (
  SELECT 
    account_id, 
    ARRAY_LENGTH(ARRAY_AGG(DISTINCT connected_id)) AS size
  FROM GRAPH_TABLE(
    fraud_demo.FraudDemo
    MATCH (a:Customer)-[:OwnsEmail|OwnsPhone|LinkedToAddress]-{4}(connected:Customer)
    RETURN a.account_id AS account_id, connected.account_id AS connected_id
  )
  GROUP BY account_id
),

prev_connect AS (
  SELECT 
    account_id, 
    ARRAY_LENGTH(ARRAY_AGG(DISTINCT connected_id)) AS size
  FROM GRAPH_TABLE(
    fraud_demo.FraudDemo
    -- Apply the timestamp filter to EVERY edge in the 4-hop chain
    MATCH (a:Customer)
          (-[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']-(n)){4}
    WHERE 'Customer' IN UNNEST(LABELS(n[OFFSET(3)]))
    RETURN a.account_id AS account_id, n[OFFSET(3)].account_id AS connected_id
  )
  GROUP BY account_id
),

edge_changes AS (
  SELECT account_id, MAX(last_updated_ts) AS max_last_updated_ts
  FROM fraud_demo.customer_addresses
  GROUP BY account_id
)

SELECT
    la.account_id,
    o.order_id,
    la.size AS latest_size,
    COALESCE(pa.size, 0) AS previous_size,
    la.size - COALESCE(pa.size, 0) AS diff,
    nos.num_order,
    o.fraud AS reported_as_fraud,
    o.order_total,

    CASE
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NULL THEN "CUSTOMER AT RISK"
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NOT NULL AND o.fraud THEN "CONFIRMED FRAUD ORDER"
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NOT NULL AND NOT o.fraud THEN "POTENTIAL FRAUD ORDER"
      ELSE ""
    END AS notes
FROM latest_connect la
LEFT JOIN prev_connect pa ON la.account_id = pa.account_id
LEFT JOIN num_orders nos ON la.account_id = nos.account_id
LEFT JOIN orders o ON la.account_id = o.account_id
INNER JOIN edge_changes ec ON la.account_id = ec.account_id
WHERE nos.num_order > 1 OR (la.size - COALESCE(pa.size, 0)) > 10
ORDER BY diff DESC

Entender os resultados

Este relatório mostra:

  • account_id: o ID da conta que está sendo analisada.
  • order_id: um ID de pedido recente.
  • latest_size: o tamanho da rede conectada hoje.
  • previous_size: o tamanho da rede há duas semanas.
  • diff: o crescimento no tamanho da rede.
  • num_order: o número de pedidos recentes.
  • reported_as_fraud: se o pedido foi marcado como fraude.
  • order_total: o valor total do pedido.
  • notes: um status de risco calculado com base no crescimento da rede e no histórico de pedidos.

Você vai encontrar contas com valores diff grandes e totais de pedidos altos, que são candidatos principais para mais investigações. As observações "CLIENTE EM RISCO" e "POSSÍVEL PEDIDO DE FRAUDE" ajudam a priorizar essas contas.

8. Detecção em escala

Nesta etapa final de análise, você vai visualizar a rede em uma escala maior. Em vez de começar com uma única conta, você vai consultar conexões entre um conjunto de contas suspeitas.

Isso ajuda a verificar se várias investigações independentes fazem parte do mesmo grupo de fraudes.

Executar a consulta escalonada

Execute a consulta a seguir no notebook.

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH
p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress]- (n) ){3, 5}
(reachable_a:Customer)
-- these IDs are from the previous results
WHERE a.account_id in (   "845f2b14-cd10-4750-9f28-fe542c4a731b"
  , "3ff59684-fbf9-40d7-8c41-285ade5002e6"
  , "8887c17b-e6fb-4b3b-8c62-cb721aafd028"
  , "03e777e5-6fb4-445d-b48c-cf42b7620874"
  , "81629832-eb1d-4a0e-86da-81a198604898"
  , "845f2b14-cd10-4750-9f28-fe542c4a731b",
   "89e9a8fe-ffc4-44eb-8693-a711a3534849"
 )
 LIMIT 400
RETURN TO_JSON(p) as paths

Entender os resultados

Essa consulta retorna um gráfico complexo que mostra como as contas suspeitas especificadas se sobrepõem e compartilham recursos. Agora você está analisando a detecção de fraudes em escala, identificando clusters de atividades que podem justificar uma resposta coordenada.

9. Limpeza

Para evitar cobranças na conta do Google Cloud em relação aos recursos usados neste codelab, exclua o conjunto de dados e o gráfico de propriedades.

Execute as instruções SQL a seguir para liberar espaço no seu ambiente.

DROP PROPERTY GRAPH IF EXISTS fraud_demo.FraudDemo;
DROP SCHEMA IF EXISTS fraud_demo CASCADE;

10. Parabéns

Parabéns! Você criou uma solução de detecção de fraudes usando o BigQuery Graph.

Você aprendeu a:

  • Carregar dados do Cloud Storage no BigQuery.
  • Definir um gráfico de propriedades usando DDL.
  • Consultar o gráfico usando GQL para encontrar relações simples e complexas.
  • Combinar a análise de grafos com dados da empresa para identificar riscos.
  • Visualizar redes em escala.

Mais recursos