L’approche courante de la sessionisation consiste à construire une table au grain session : une ligne par session avec des métriques agrégées comme la durée, les pages vues et les revenus. Cela fonctionne pour les rapports de base, mais élimine le détail au niveau événement.
Une fois agrégé au grain session, la séquence des événements, le timing entre les interactions et les pages spécifiques consultées se résument en métriques sommaires. Répondre à des questions comme « quelles pages les utilisateurs visitent-ils avant d’acheter ? » nécessite de faire une jointure avec les événements bruts. « Combien de temps après l’atterrissage les utilisateurs ajoutent-ils au panier ? » nécessite les horodatages d’événements qui ont été agrégés.
L’alternative au grain événement
Au lieu de construire les sessions comme sortie, ajoutez le contexte de session sous forme de colonnes sur chaque événement. Chaque ligne reste un événement individuel, mais porte désormais son identité de session, la source de trafic de la session, la page d’atterrissage et sa position dans la séquence de la session.
Le pattern utilise des window functions pour propager les valeurs au niveau session sur chaque événement d’une session. FIRST_VALUE récupère la source de trafic depuis le premier événement. MIN et MAX établissent les bornes de la session. ROW_NUMBER assigne des positions de séquence. Tout cela se fait sans changer le grain — chaque ligne d’événement reste intacte.
SELECT event_date, event_timestamp, event_name, session_key,
-- Contexte de session ajouté via les window functions MIN(event_timestamp) OVER (PARTITION BY session_key) AS session__started_at, MAX(event_timestamp) OVER (PARTITION BY session_key) AS session__ended_at, FIRST_VALUE(source IGNORE NULLS) OVER w AS session__source, FIRST_VALUE(landing_page IGNORE NULLS) OVER w AS session__landing_page, ROW_NUMBER() OVER w AS event__number_in_session
WINDOW w AS (PARTITION BY session_key ORDER BY event_timestamp)Le résultat est une table d’événements enrichis où chaque ligne porte son contexte de session complet sous forme de colonnes supplémentaires.
Ce que cela permet
Les requêtes qui nécessitaient des jointures complexes avec une table au grain session deviennent simples :
- « Montrez-moi tous les événements dans les sessions qui ont converti » — une clause WHERE filtrant sur les événements où
session_keyapparaît avec un événement d’achat. - « Quel est le temps moyen entre le début de la session et le premier ajout au panier ? » —
event_timestamp - session__started_atfiltré surevent_name = 'add_to_cart'. - « Quelles pages d’atterrissage conduisent au plus long engagement de session ? » — un GROUP BY sur
session__landing_pageavec les horodatages au niveau événement.
La table au grain session devient triviale
La table au grain session dont vous pourriez encore avoir besoin pour les tableaux de bord devient un simple dérivé. Tout le contexte de session existe déjà sur chaque ligne, donc l’agrégation ne nécessite aucune jointure :
SELECT session_key, ANY_VALUE(session__source) AS session__source, ANY_VALUE(session__medium) AS session__medium, ANY_VALUE(session__landing_page) AS session__landing_page, MIN(event_timestamp) AS session__started_at, MAX(event_timestamp) AS session__ended_at, COUNT(*) AS session__events, COUNTIF(event_name = 'page_view') AS session__page_views, COUNTIF(event_name = 'purchase') AS session__purchasesFROM sessionized_eventsGROUP BY session_keyANY_VALUE fonctionne pour les dimensions au niveau session parce que les window functions ont déjà propagé la même valeur sur tous les événements d’une session. Pas de jointures, pas de sous-requêtes, juste un GROUP BY sur la clé de session.
Cela suit le principe de la couche mart : la table d’événements enrichis est un modèle intermédiaire qui préserve le grain événement, et le mart de sessions l’agrège pour la consommation par les tableaux de bord. Une seule source de vérité, plusieurs formes de sortie.
Le compromis : le stockage
Le compromis est le stockage. Ajouter des colonnes de session à chaque ligne d’événement signifie une table plus large. Sur une propriété à fort trafic, ce sont des octets supplémentaires significatifs. Mais le stockage en colonnes de BigQuery signifie que les requêtes ne lisent que les colonnes qu’elles référencent, donc les colonnes de session inutilisées n’ajoutent pas de coût de requête. Et l’élagage de partitions limite le nombre de jours scannés indépendamment de la largeur des lignes.
L’alternative — maintenir à la fois une table au grain session et retourner aux événements bruts pour des analyses ad-hoc — coûte davantage en temps d’ingénierie et introduit des risques de cohérence lorsque deux tables divergent.
Quand le grain session suffit
Tous les projets n’ont pas besoin de la sessionisation au grain événement. Si vos exigences analytics se limitent aux métriques de session standard (comptages, durée, taux de rebond, taux de conversion) et que personne ne pose de questions sur les séquences d’événements, une table au grain session est plus simple et suffisante.
La décision dépend des questions que vous anticipez. Si « qu’est-il arrivé avant la conversion ? » ou « quelle est la séquence d’événements dans les sessions issues de la recherche payante ? » sont au programme, commencez avec le grain événement. Migrer d’un grain session à un grain événement plus tard signifie reconstruire l’ensemble du pipeline.
Flux d’implémentation
L’implémentation pratique dans dbt suit cette lignée :
- Modèle de base (
base__ga4__events) : extraction depuis l’export brut, nettoyage des types, filtrage des enregistrements invalides - Modèle intermédiaire (
int__ga4__events_sessionized) : ajout de la clé de session, du contexte de session via les window functions, du positionnement des événements - Modèle mart (
mrt__ga4__sessions) : GROUP BY sur la clé de session pour la consommation par les tableaux de bord
Le modèle intermédiaire est le plus exigeant. C’est là que se produit la sessionisation, et c’est là que le traitement incrémental est le plus important car les tables d’événements grossissent vite. Le mart est simplement une couche d’agrégation par-dessus.
Lorsque les exigences changent, ajouter une nouvelle métrique au niveau session signifie l’ajouter dans le SELECT du mart. Changer la logique d’attribution de session signifie modifier le modèle intermédiaire une seule fois ; le mart hérite automatiquement de la correction.