Detección de fraudes con BigQuery Graph

1. Introducción

Encabezado de marketing: Fraude en la tecnología financiera

La actividad fraudulenta suele involucrar redes ocultas de entidades conectadas, por ejemplo, varias cuentas que comparten la misma dirección de correo electrónico, número de teléfono o dirección física. Las bases de datos relacionales tradicionales pueden tener dificultades para consultar estas relaciones complejas de varios saltos de manera eficiente.

BigQuery Graph te permite analizar estas redes a gran escala con bases de datos de grafos. Puedes definir un grafo de propiedades sobre tus tablas de BigQuery existentes y usar Graph Query Language (GQL) para encontrar patrones en tus datos.

Una aplicación común de las redes de grafos para la detección de fraudes es detener los pedidos que tienen una dirección de entrega asociada con una red de fraude o detener los pagos que pertenecen a .

En este codelab, crearás una solución de detección de fraudes con BigQuery Graph. Cargarás datos de Cloud Storage, crearás un grafo de propiedades y usarás consultas de grafos para identificar conexiones sospechosas.

Qué aprenderás

  • Cómo crear un conjunto de datos de BigQuery y cargar datos
  • Cómo definir un grafo de propiedades con DDL
  • Cómo consultar el grafo con GQL
  • Cómo usar el análisis de grafos para detectar fraudes

Requisitos

  • Un proyecto de Google Cloud con facturación habilitada.
  • Un entorno de notebooks de BigQuery (BigQuery Studio o Colab Enterprise)

Costo

En este lab, se usan recursos facturables de Google Cloud. El costo estimado es inferior a USD 5, suponiendo que borres los recursos después de completar el proceso.

2. Antes de comenzar

Selecciona o crea un proyecto de Google Cloud

  1. En la página del selector de proyectos de Google Cloud Console, selecciona o crea un proyecto de Google Cloud.
  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información para verificar si la facturación está habilitada.

Elige tu entorno

Necesitarás un entorno de notebook para ejecutar este lab. Puedes usar BigQuery Studio o Colab Enterprise.

  1. Navega a la página de BigQuery en la consola de Google Cloud.
  2. Usarás el notebook de Python para ejecutar las consultas de grafos.

Inicie Cloud Shell

  1. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud.
  2. Verifica la autenticación:
gcloud auth list
  1. Confirma tu proyecto:
gcloud config get project
  1. Establécelo si es necesario:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID

Habilita las APIs

Ejecuta este comando para habilitar la API de BigQuery requerida:

gcloud services enable bigquery.googleapis.com \
  bigqueryreservation.googleapis.com 

Crea una reserva y una asignación de BigQuery

Para ejecutar consultas de GQL, debes tener una reserva que use la edición Enterprise o Enterprise Plus. Crea una reserva de la edición Enterprise con ajuste de escala automático en Cloud Shell:

# 1. Create a BigQuery Enterprise reservation with 0 baseline slots and 100 max autoscaling slots
bq mk --reservation \
  --project_id=${GCP_PROJECT} \
  --location=US \
  --edition=ENTERPRISE \
  --slots=0 \
  --autoscale_max_slots=100 \
  --ignore_idle_slots=true \
  fraud-reservation

# 2. Assign your Cloud project to the newly created reservation for query execution
bq mk --reservation_assignment \
  --project_id=${GCP_PROJECT} \
  --location=US \
  --reservation_id=fraud-reservation \
  --job_type=QUERY \
  --assignee_type=PROJECT \
  --assignee_id=${GCP_PROJECT}

3. Cargar datos

En este paso, crearás un conjunto de datos de BigQuery y cargarás la muestra de datos desde Cloud Storage.

Los datos de muestra constan de varios archivos CSV que representan un entorno de venta minorista simulado:

  • customers.csv: Información de la cuenta del cliente.
  • emails.csv: Direcciones de correo electrónico.
  • phones.csv: Números de teléfono.
  • addresses.csv: Direcciones físicas
  • customer_emails.csv, customer_phones.csv, customer_addresses.csv: Vinculación de tablas.
  • orders.csv: Historial de pedidos, incluidos los indicadores de fraude

Crea el conjunto de datos

Crea un conjunto de datos llamado fraud_demo para almacenar las tablas.

  1. En este codelab, ejecutaremos comandos de SQL. Puedes ejecutar estos comandos en BigQuery Studio > Editor de SQL o usar el comando bq query en Cloud Shell. Nueva consulta en SQLSupondremos que usarás el editor de SQL de BigQuery para tener una mejor experiencia con las declaraciones de creación de varias líneas.
CREATE SCHEMA IF NOT EXISTS `fraud_demo` OPTIONS(location="US");

Carga tablas

Ejecuta las siguientes sentencias de SQL para cargar datos de Cloud Storage en tu conjunto de datos.

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. Crea el grafo de propiedades

Ahora que se cargaron los datos, puedes definir el grafo de propiedades. Un grafo de propiedades consta de nodos (entidades) y aristas (relaciones).

En este lab, los nodos son los siguientes:

  • Cliente: Representa al titular de la cuenta.
  • Teléfono: Representa un número de teléfono.
  • Correo electrónico: Representa una dirección de correo electrónico.
  • Dirección: Representa una dirección física.

Los bordes son los siguientes:

  • OwnsPhone: Conecta un cliente a un teléfono.
  • OwnsEmail: Conecta un cliente con un correo electrónico.
  • LinkedToAddress: Conecta un cliente con una dirección.

Crea el gráfico

Ejecuta la siguiente sentencia de DDL para crear el grafo llamado FraudDemo en tu conjunto de datos 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. Analiza redes (2 saltos)

Abre Nuevo notebook en BigQuery Studio.

Crear un cuaderno nuevo

Para las partes de visualización y recomendación de este codelab, usaremos un notebook de Google Colab en BigQuery Studio. Esto nos permite visualizar fácilmente los resultados del gráfico.

Pega lo siguiente en una celda de código:

!pip install bigquery-magics==0.12.1

El notebook de BigQuery Graph se implementa como un comando mágico de IPython. Si agregas el comando mágico %%bigquery con la función TO_JSON, puedes visualizar los resultados como se muestra en las siguientes secciones. En este paso, ejecutarás una consulta de grafo para encontrar conexiones simples entre cuentas. Esta es una consulta de "2 saltos" porque recorre 2 saltos desde un nodo inicial para encontrar nodos relacionados (p.ej., Cliente -> Correo electrónico -> Cliente).

Comenzaremos investigando la cuenta que pertenece a Nicole Wade. Queremos encontrar cualquier cuenta relacionada con ella a través de 2 saltos.

Ejecuta la consulta de 2 saltos

Ejecuta la siguiente consulta en tu 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

Cómo interpretar los resultados

La consulta realiza las siguientes acciones:

  1. Comienza en el nodo Customer con account_id "d2f1f992-d116-41b3-955b-6c76a3352657" (Nicole Wade).
  2. Sigue cualquiera de los bordes OwnsEmail, OwnsPhone o LinkedToAddress hasta un nodo de conexión (Phone, Email o Address).
  3. Sigue las aristas desde ese nodo de conexión hasta otros nodos Customer.
  4. Filtra los bordes según una marca de tiempo (last_updated_ts) para ver el estado de la red en un momento específico.

Deberías ver que Zachary Cordova y Brenda Brown están conectados a Nicole a través de la misma dirección.

6. Analiza redes (4 saltos)

En este paso, extenderás la consulta para encontrar relaciones más complejas. Buscaremos conexiones de 4 saltos. Esto nos permite encontrar cuentas que están conectadas a través de varias entidades intermedias (p.ej., Cliente A -> Correo electrónico -> Cliente B -> Teléfono -> Cliente C).

También observaremos cómo cambia esta red con el tiempo.

El estado "antes"

Primero, veamos la red tal como existía el 30 de julio de 2025.

Ejecute la siguiente consulta:

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
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)]))
RETURN 
  TO_JSON(p) AS paths,                   -- Array of all traversed edges
  ARRAY_LENGTH(e) AS hop_count

El estado "después"

Ahora, veamos cómo se ve la red 2 semanas después. Ejecutaremos la misma consulta, pero sin las restricciones de fecha.

Ejecute la siguiente 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

Cómo interpretar los resultados

Si quitas los filtros de fecha, realizarás la consulta en todo el conjunto de datos. Notarás que la red creció de forma significativa. Nicole Wade ahora forma parte de un grupo mucho más grande y conectado. Esta rápida expansión de una red conectada es un indicador sólido de una actividad potencialmente fraudulenta, como una red de fraude que comparte recursos a lo largo del tiempo.

7. Generar informe de fraude

En este paso, combinarás el análisis de grafos con los datos empresariales tradicionales (pedidos) para generar un informe de fraude integral. Identificarás las cuentas en riesgo y los posibles pedidos fraudulentos.

Esta consulta es más compleja. Usa GRAPH_TABLE para ejecutar la consulta de grafo dentro de SQL estándar y calcula el cambio en el tamaño de la red (diff) entre los estados "antes" y "después" que observamos en el paso anterior.

Ejecuta la consulta del informe de fraude

Ejecuta la siguiente consulta en tu 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

Cómo interpretar los resultados

En este informe, se muestra lo siguiente:

  • account_id: Es el ID de la cuenta que se analiza.
  • order_id: Es el ID de un pedido reciente.
  • latest_size: El tamaño de la red conectada hoy.
  • previous_size: Es el tamaño de la red hace 2 semanas.
  • diff: El crecimiento en el tamaño de la red.
  • num_order: Es la cantidad de pedidos recientes.
  • reported_as_fraud: Indica si el pedido se marcó como fraudulento.
  • order_total: Es el importe total del pedido.
  • notes: Es un estado de riesgo calculado en función del crecimiento de la red y el historial de pedidos.

Verás cuentas con valores de diff altos y totales de pedidos elevados, que son candidatos ideales para una investigación más detallada. Las notas "CLIENTE EN RIESGO" y "PEDIDO CON POSIBLE FRAUDE" ayudan a priorizar estas cuentas.

8. Detección a gran escala

En este paso final del análisis, visualizarás la red a mayor escala. En lugar de comenzar con una sola cuenta, consultarás las conexiones entre un conjunto de cuentas sospechosas.

Esto te ayuda a ver si varias investigaciones independientes en realidad forman parte de la misma red de fraude más grande.

Ejecuta la consulta escalada

Ejecuta la siguiente consulta en tu 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

Cómo interpretar los resultados

Esta consulta devuelve un grafo complejo que muestra cómo las cuentas sospechosas especificadas se superponen y comparten recursos. Ahora estás analizando la detección de fraudes a gran escala, identificando clústeres de actividad que podrían requerir una respuesta coordinada.

9. Limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en este codelab, debes borrar el conjunto de datos y el grafo de propiedades.

Ejecuta las siguientes sentencias de SQL para limpiar tu entorno.

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

10. Felicitaciones

¡Felicitaciones! Creaste correctamente una solución de detección de fraudes con BigQuery Graph.

Aprendiste a realizar las siguientes actividades:

  • Cargar datos de Cloud Storage en BigQuery
  • Definir un grafo de propiedades con DDL
  • Consulta el grafo con GQL para encontrar relaciones simples y complejas.
  • Combina el análisis de grafos con los datos de la empresa para identificar riesgos.
  • Visualiza redes a gran escala.

Más recursos