1. Introduzione

L'attività fraudolenta spesso coinvolge reti nascoste di entità connesse, ad esempio più account che condividono lo stesso indirizzo email, numero di telefono o indirizzo fisico. I database relazionali tradizionali possono avere difficoltà a eseguire query in modo efficiente su queste relazioni complesse e multi-hop.
BigQuery Graph ti consente di analizzare queste reti su larga scala utilizzando i database di grafici. Puoi definire un grafico delle proprietà sulle tabelle BigQuery esistenti e utilizzare Graph Query Language (GQL) per trovare pattern nei dati.
Un'applicazione comune delle reti di grafici per il rilevamento delle frodi è l'interruzione degli ordini con un indirizzo di consegna associato a una rete di frodi o l'interruzione dei pagamenti appartenenti a .
In questo codelab creerai una soluzione di rilevamento delle frodi utilizzando BigQuery Graph. Caricherai i dati da Cloud Storage, creerai un grafico delle proprietà e utilizzerai le query sui grafici per identificare le connessioni sospette.
Obiettivi didattici
- Come creare un set di dati BigQuery e caricare i dati.
- Come definire un grafico delle proprietà utilizzando DDL.
- Come eseguire query sul grafico utilizzando GQL.
- Come utilizzare l'analisi dei grafici per rilevare le frodi.
Che cosa ti serve
- Un progetto Google Cloud con la fatturazione abilitata.
- Un ambiente notebook BigQuery (BigQuery Studio o Colab Enterprise).
Costo
Questo lab utilizza risorse Google Cloud fatturabili. Il costo stimato è inferiore a 5 $, presupponendo che tu elimini le risorse al termine.
2. Prima di iniziare
Seleziona o crea un progetto Google Cloud
- Nella console Google Cloud, nella pagina di selezione del progetto, seleziona o crea un progetto Google Cloud.
- Verifica che la fatturazione sia attivata per il tuo progetto Google Cloud. Scopri come verificare se la fatturazione è abilitata.
Scegli il tuo ambiente
Per eseguire questo lab, avrai bisogno di un ambiente notebook. Puoi utilizzare BigQuery Studio o Colab Enterprise.
- Vai alla pagina BigQuery nella console Google Cloud.
- Utilizzerai il notebook Python per eseguire le query sui grafici.
Avvia Cloud Shell
- Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.
- Verifica l'autenticazione:
gcloud auth list
- Conferma il progetto:
gcloud config get project
- Impostalo se necessario:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
Abilita API
Esegui questo comando per abilitare l'API BigQuery richiesta:
gcloud services enable bigquery.googleapis.com
3. Carica dati
In questo passaggio creerai un set di dati BigQuery e caricherai i dati di esempio da Cloud Storage.
I dati di esempio sono costituiti da diversi file CSV che rappresentano un ambiente di vendita al dettaglio simulato:
customers.csv: informazioni sull'account cliente.emails.csv: indirizzi email.phones.csv: numeri di telefono.addresses.csv: indirizzi fisici.customer_emails.csv,customer_phones.csv,customer_addresses.csv: tabelle di collegamento.orders.csv: cronologia degli ordini, inclusi i flag di frode.
Crea il set di dati
Crea un set di dati denominato fraud_demo per contenere le tabelle.
- Per questo codelab, eseguiremo i comandi SQL. Puoi eseguire questi comandi in BigQuery Studio > Editor SQL oppure utilizzare il
bq querycomando in Cloud Shell.
Supponiamo che tu stia utilizzando l'editor SQL di BigQuery per un'esperienza migliore con le istruzioni di creazione su più righe.
CREATE SCHEMA IF NOT EXISTS `fraud_demo` OPTIONS(location="US");
Carica tabelle
Esegui le seguenti istruzioni SQL per caricare i dati da Cloud Storage nel set di dati.
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 il grafico delle proprietà
Ora che i dati sono caricati, puoi definire il grafico delle proprietà. Un grafico delle proprietà è costituito da nodi (entità) e bordi (relazioni).
In questo lab, i nodi sono:
- Cliente: rappresenta il titolare dell'account.
- Telefono: rappresenta un numero di telefono.
- Email: rappresenta un indirizzo email.
- Indirizzo: rappresenta un indirizzo fisico.
I bordi sono:
- OwnsPhone: collega un cliente a un telefono.
- OwnsEmail: collega un cliente a un'email.
- LinkedToAddress: collega un cliente a un indirizzo.

Crea il grafico
Esegui la seguente istruzione DDL per creare il grafico denominato FraudDemo nel set di dati 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. Analizza le reti (2-hop)
Apri Nuovo notebook in BigQuery Studio.

Per le parti di visualizzazione e suggerimenti di questo codelab, utilizzeremo un notebook Google Colab in BigQuery Studio. In questo modo possiamo visualizzare facilmente i risultati del grafico.
Il notebook BigQuery Graph è implementato come IPython Magics. Aggiungendo il comando magico %%bigquery con la funzione TO_JSON, puoi visualizzare i risultati come mostrato nelle sezioni seguenti. In questo passaggio, eseguirai una query sui grafici per trovare connessioni semplici tra gli account. Si tratta di una query "2-hop" perché percorre 2 hop da un nodo iniziale per trovare i nodi correlati (ad es. Cliente -> Email -> Cliente).
Inizieremo esaminando l'account di Nicole Wade. Vogliamo trovare tutti gli account correlati al suo tramite 2 hop.
Esegui la query 2-hop
Esegui la seguente query nel 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

Cosa significano i risultati
Questa query:
- Inizia dal nodo
Customerconaccount_id"d2f1f992-d116-41b3-955b-6c76a3352657" (Nicole Wade). - Segue uno dei bordi
OwnsEmail,OwnsPhoneoLinkedToAddressa un nodo di collegamento (Phone,EmailoAddress). - Segue i bordi dal nodo di collegamento ad altri nodi
Customer. - Filtra i bordi in base a un timestamp (
last_updated_ts) per visualizzare lo stato della rete in un momento specifico.
Dovresti vedere che Zachary Cordova e Brenda Brown sono collegati a Nicole tramite lo stesso indirizzo.
6. Analizza le reti (4-hop)
In questo passaggio, estenderai la query per trovare relazioni più complesse. Cercheremo le connessioni 4-hop. In questo modo possiamo trovare gli account collegati tramite diverse entità intermedie (ad es. Cliente A -> Email -> Cliente B -> Telefono -> Cliente C).
Osserveremo anche come questa rete cambia nel tempo.
Lo stato "Prima"
Innanzitutto, esaminiamo la rete così com'era il 30 luglio 2025.
Esegui la seguente query:
%%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

Lo stato "Dopo"
Ora vediamo come appare la rete 2 settimane dopo. Eseguiremo la stessa query, ma senza le limitazioni di data.
Esegui la seguente query:
%%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

Cosa significano i risultati
Se rimuovi i filtri della data, esegui una query sull'intero set di dati. Noterai che la rete è cresciuta in modo significativo. Nicole Wade fa ora parte di un gruppo molto più grande e altamente connesso. Questa rapida espansione di una rete connessa è un forte indicatore di attività potenzialmente fraudolenta, ad esempio un anello di frodi che condivide le risorse nel tempo.
7. Genera report sulle frodi
In questo passaggio, combinerai l'analisi dei grafici con i dati aziendali tradizionali (ordini) per generare un report completo sulle frodi. Identificherai gli account a rischio e i potenziali ordini fraudolenti.
Questa query è più complessa. Utilizza GRAPH_TABLE per eseguire la query sui grafici all'interno di SQL standard e calcola la variazione delle dimensioni della rete (diff) tra gli stati "prima" e "dopo" osservati nel passaggio precedente.
Esegui la query del report sulle frodi
Esegui la seguente query nel 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
Cosa significano i risultati
Questo report mostra:
account_id: l'ID dell'account in fase di analisi.order_id: un ID ordine recente.latest_size: le dimensioni della rete connessa oggi.previous_size: le dimensioni della rete 2 settimane fa.diff: la crescita delle dimensioni della rete.num_order: il numero di ordini recenti.reported_as_fraud: indica se l'ordine è stato contrassegnato come frode.order_total: l'importo totale dell'ordine.notes: uno stato di rischio calcolato in base alla crescita della rete e alla cronologia degli ordini.
Vedrai gli account con valori diff elevati e totali degli ordini elevati, che sono i candidati principali per ulteriori indagini. Le note "CLIENTE A RISCHIO" e "ORDINE POTENZIALMENTE FRAUDOLENTO" consentono di dare la priorità a questi account.

8. Rilevamento su larga scala
In questo passaggio di analisi finale, visualizzerai la rete su una scala più ampia. Anziché iniziare con un singolo account, eseguirai una query per le connessioni tra un insieme di account sospetti.
In questo modo puoi verificare se più indagini indipendenti fanno effettivamente parte dello stesso anello di frodi più grande.
Esegui la query scalata
Esegui la seguente query nel 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
Cosa significano i risultati
Questa query restituisce un grafico complesso che mostra la sovrapposizione e la condivisione delle risorse degli account sospetti specificati. Ora stai esaminando il rilevamento delle frodi su larga scala, identificando i cluster di attività che potrebbero giustificare una risposta coordinata.

9. Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo codelab, devi eliminare il set di dati e il grafico delle proprietà.
Esegui le seguenti istruzioni SQL per liberare spazio nell'ambiente.
DROP PROPERTY GRAPH IF EXISTS fraud_demo.FraudDemo;
DROP SCHEMA IF EXISTS fraud_demo CASCADE;
10. Complimenti
Complimenti! Hai creato correttamente una soluzione di rilevamento delle frodi utilizzando BigQuery Graph.
Hai imparato a:
- Caricare i dati in BigQuery da Cloud Storage.
- Definire un grafico delle proprietà utilizzando DDL.
- Eseguire query sul grafico utilizzando GQL per trovare relazioni semplici e complesse.
- Combinare l'analisi dei grafici con i dati aziendali per identificare i rischi.
- Visualizzare le reti su larga scala.
Altre risorse