
Sessionization and behavioral grouping
Sessionization and behavioral grouping. Core lesson of the Advanced SQL for Analytical Systems module with real problem, conceptual model, rigorous formalization, applied case, 3-level lab, and final checkpoint.
What you will learn
- Understand the analytical problem and the decision-making context
- Apply examples, metrics, and controls to real cases
Sessionization e raggruppamento comportamentale
Un utente apre l’app alle 8:02, torna alle 8:37, clicca tre prodotti e poi sparisce fino al pomeriggio. Nel log ci sono solo eventi ordinati nel tempo, ma per chi lavora sul prodotto quei blocchi diventano sessioni, intenzioni e segnali di attrito. La sessionizzazione e il raggruppamento comportamentale servono a costruire questo livello intermedio senza inventare storie che i dati non sostengono.
Il problema da risolvere
Con SQL avanzato il compito è trasformare eventi grezzi in unità di analisi stabili e significative. Decidere cosa è una sessione, quale soglia temporale usare e come raggruppare i comportamenti incide direttamente su metriche come conversioni, retention e diagnosi dell’esperienza utente. La soglia temporale è una scelta di business, non tecnica: deve riflettere il comportamento reale che vuoi catturare.
Come ragionare sul raggruppamento
Uno schema essenziale guida ogni approfondimento tecnico, che deve rafforzare almeno una di queste quattro fasi.
| Phase | What to clarify | Output |
|---|---|---|
| Question | Quale decisione reale vogliamo migliorare? | Decision to make |
| Measure | Which observable signal represents the problem? | Metric or source data |
| Control | Which baseline makes the result interpretable? | Credible comparison |
| Action | What changes after the analysis? | Next operational step |
Rendere l’analisi riproducibile
Perché la sessionizzazione sia analizzabile servono alcune definizioni precise, dall’unità di analisi al rischio da tenere d’occhio.
| Element | Requested specification |
|---|---|
| Unit of analysis | Riga, partizione, finestra, join, coorte o metrica temporale |
| Primary signal | Correttezza, performance, duplicati, grain e stabilità del risultato |
| Baseline | Previous period, comparable group, benchmark, or counterfactual scenario |
| Decision | Query, modello intermedio, test SQL o pattern riusabile |
| Risk | Mistaking an available number for sufficient proof |
La formalizzazione regge quando un altro analista, partendo dagli stessi dati, può riprodurre la logica e arrivare alla stessa decisione.
Il pattern SQL della sessionizzazione
Gli eventi utente arrivano come righe isolate, ma la decisione richiede sessioni e sequenze raggruppate. Sessionizzare significa fissare soglia di inattività, ordinamento, identità e confini della sessione prima di interpretare conversione o engagement.
Il primo passaggio individua dove inizia una nuova sessione. Una nuova sessione comincia quando l’evento è il primo dell’utente oppure quando dal contatto precedente sono passati più di 1800 secondi:
WITH events_with_gap AS (
SELECT
user_id,
event_time,
event_type,
LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_event_time,
CASE
WHEN LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) IS NULL THEN 1
WHEN EXTRACT(EPOCH FROM (event_time - LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time))) > 1800 THEN 1
ELSE 0
END AS is_new_session
FROM raw_events
)
Il secondo passaggio assegna un numero progressivo alla sessione con una somma cumulativa:
events_with_session AS (
SELECT *,
SUM(is_new_session) OVER (PARTITION BY user_id ORDER BY event_time ROWS UNBOUNDED PRECEDING) AS session_number
FROM events_with_gap
)
SELECT
user_id,
session_number,
MIN(event_time) AS session_start,
MAX(event_time) AS session_end,
COUNT(*) AS events_in_session,
EXTRACT(EPOCH FROM (MAX(event_time) - MIN(event_time))) AS session_duration_s
FROM events_with_session
GROUP BY user_id, session_number;
The session_number è un contatore cumulativo che parte da 1 per ogni utente e cresce a ogni nuova sessione.
Dal gap temporale ai cambi di stato
Oltre al gap temporale capita di dover raggruppare eventi per cambi di stato o pattern sequenziali. In una tabella di sensori IoT che misurano la temperatura ogni minuto, per esempio, può servire raggruppare gli episodi di surriscaldamento, cioè le temperature consecutive sopra i 30°C.
WITH temp_flagged AS (
SELECT
sensor_id,
measured_at,
temperature,
CASE WHEN temperature > 30 THEN 0 ELSE 1 END AS state,
LAG(CASE WHEN temperature > 30 THEN 0 ELSE 1 END) OVER (PARTITION BY sensor_id ORDER BY measured_at) AS prev_state
FROM sensor_readings
),
state_changes AS (
SELECT *,
CASE WHEN state != prev_state OR prev_state IS NULL THEN 1 ELSE 0 END AS is_new_episode
FROM temp_flagged
)
SELECT
sensor_id,
SUM(is_new_episode) OVER (PARTITION BY sensor_id ORDER BY measured_at ROWS UNBOUNDED PRECEDING) AS episode_id,
MIN(measured_at) AS episode_start,
MAX(measured_at) AS episode_end,
MAX(temperature) AS peak_temp
FROM state_changes
WHERE state = 0 -- solo episodi di surriscaldamento
GROUP BY sensor_id, episode_id
HAVING COUNT(*) >= 5; -- almeno 5 minuti consecutivi
Il pattern è lo stesso della sessionizzazione, solo che il trigger è un cambio di stato logico invece di un gap temporale.
Un caso applicato: Tesla e le sessioni di guida
Tesla raccoglie dati da milioni di veicoli connessi e genera volumi enormi di eventi telemetrici. Per il team Autopilot la sessionizzazione serve a raggruppare gli eventi in viaggi distinti, e la definizione di viaggio non è banale: una sosta di 2 minuti a un semaforo non interrompe il viaggio, mentre una sosta di 15 minuti in area di servizio può interromperlo, a seconda dello stato del motore e della posizione.
WITH vehicle_events AS (
SELECT
vin,
event_time,
gear, -- 'P', 'D', 'R', 'N'
speed,
lat, lon,
LAG(gear) OVER (PARTITION BY vin ORDER BY event_time) AS prev_gear,
LAG(lat) OVER (PARTITION BY vin ORDER BY event_time) AS prev_lat,
LAG(lon) OVER (PARTITION BY vin ORDER BY event_time) AS prev_lon
FROM telemetry
),
trip_starts AS (
SELECT *,
CASE
WHEN prev_gear IS NULL THEN 1
WHEN prev_gear = 'P' AND gear = 'D'
AND haversine(prev_lat, prev_lon, lat, lon) > 0.1
THEN 1
ELSE 0
END AS is_new_trip
FROM vehicle_events
)
SELECT vin,
SUM(is_new_trip) OVER (PARTITION BY vin ORDER BY event_time ROWS UNBOUNDED PRECEDING) AS trip_id,
COUNT(*) AS events,
MAX(speed) AS max_speed,
MAX(event_time) - MIN(event_time) AS duration
FROM trip_starts
GROUP BY vin, trip_id;
Spostando la sessionizzazione lato server in batch, Tesla ha ridotto in modo netto i costi computazionali.
Esercitarsi sui dati
Per allenarsi vanno bene dati di clickstream, ordini, sessioni, coorti e tabelle temporali, e in mancanza di dati reali basta un dataset sintetico con almeno 200 righe. Un primo esercizio consiste nello scrivere la query di sessionizzazione con soglia di 30 minuti su un dataset clickstream. Da lì si estende la logica facendo terminare una sessione anche quando l’utente raggiunge la pagina thank_you. L’esercizio più impegnativo è attribuire ogni sessione al canale del primo evento usando FIRST_VALUE.
L’errore tipico da evitare
L’errore più comune è usare sessionization e behavioral grouping come etichetta senza collegare i risultati a una decisione concreta. Senza baseline e senza dire quale assunzione potrebbe invalidare il risultato, l’analisi rischia di essere inutile o fuorviante.
Per verificare di avere capito, prova a spiegare cosa definisce una sessione e perché la soglia è una scelta di business, qual è il pattern SQL a due passaggi della sessionizzazione, come estenderesti la logica per raggruppare per cambi di stato, quale errore tipico può invalidare una conclusione e quale output consegneresti a uno stakeholder non tecnico.
Operational Summary
Sessionization e behavioral grouping diventano strumenti efficaci solo quando producono decisioni più chiare e azioni concrete. Lo stesso percorso vale sempre: problema, schema di ragionamento, formalizzazione, esempio, esercizio e controllo della comprensione, e così la teoria diventa pratica applicata.
Academic references: Kaushik (2010), Google Analytics Help (2024), Suthar & Patel (2023).
Quality control
Prima di usare la sessionizzazione in decisioni operative, verifica completezza, duplicati, timezone, definizioni cambiate e segmenti esclusi. Molte analisi falliscono perché il dato misura un comportamento diverso da quello che il team crede di osservare.
Related Path
Lessons to read together
Questi collegamenti portano la lezione dentro il resto del corso: basi da riprendere, passaggi successivi e connessioni tematiche tra moduli.