0% ont trouvé ce document utile (0 vote)
2 vues51 pages

Cours Apache Pinot Spring Boot

Ce document présente Apache Pinot, un système de gestion de données conçu pour le traitement analytique en temps réel. Il couvre des sujets tels que l'architecture OLTP et OLAP, la modélisation des données, l'ETL, et l'indexation avancée, tout en incluant des cas d'usage industriels et des comparaisons avec d'autres solutions. L'auteur, Dr. Badr El Khalyly, propose également un projet complet utilisant Spring Boot.

Transféré par

BADR EL KHALYLY
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues51 pages

Cours Apache Pinot Spring Boot

Ce document présente Apache Pinot, un système de gestion de données conçu pour le traitement analytique en temps réel. Il couvre des sujets tels que l'architecture OLTP et OLAP, la modélisation des données, l'ETL, et l'indexation avancée, tout en incluant des cas d'usage industriels et des comparaisons avec d'autres solutions. L'auteur, Dr. Badr El Khalyly, propose également un projet complet utilisant Spring Boot.

Transféré par

BADR EL KHALYLY
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Apache Pinot

appliqué avec
Spring Boot
OLTP  OLAP  Data Warehouse  ETL  Docker
Théorie, modélisation, pratique et projet complet

Auteur
Dr. BADR EL KHALYLY
Table des matières

1 Introduction à Apache Pinot 4


1.1 Contexte : l'explosion des données analytiques . . . . . . . . . . . . . . . . . . . . . 4
1.2 Qu'est-ce qu'Apache Pinot ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Historique et évolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Positionnement d'Apache Pinot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5 Caractéristiques clés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.6 Cas d'usage industriels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.7 Comparaison avec les alternatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.8 Écosystème Apache Pinot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 OLTP vs OLAP : comparaison approfondie 7


2.1 Dénitions fondamentales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Architecture OLTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Architecture OLAP avec Pinot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Tableau comparatif OLTP vs OLAP . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Modélisation dimensionnelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3 Schéma relationnel OLTP 10


3.1 Principes de la modélisation relationnelle . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2 Modèle métier : e-commerce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.3 Schéma relationnel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.4 Script DDL Postgres complet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.5 Contraintes d'intégrité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

4 Data Warehouse et schéma en étoile 13


4.1 Pourquoi un Data Warehouse ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.2 Schéma en étoile (Star Schema) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.3 Schéma DW en étoile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4 Table de faits : détail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.5 Typologie des dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.6 SCD : Slowly Changing Dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.7 Schéma en ocon vs étoile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.8 Schéma en ocon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

5 Conception ETL et mapping 17


5.1 Diagramme du pipeline ETL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5.2 Extract : les sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5.3 Transform : les règles de transformation . . . . . . . . . . . . . . . . . . . . . . . . 17
5.4 Load : les stratégies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5.5 Table de mapping ETL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5.6 Orchestration du pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

6 Architecture interne d'Apache Pinot 19


6.1 Les composants du cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.2 Segments : unité de stockage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.3 Tables OFFLINE, REALTIME, HYBRID . . . . . . . . . . . . . . . . . . . . . . . 19
6.4 Tenants et isolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.5 Cycle de vie d'un segment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.6 Flux d'une requête SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

7 Indexation avancée 21
7.1 Les types d'index Pinot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.1 Forward Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.2 Dictionary Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.3 Inverted Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.4 Sorted Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.5 Range Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.6 Bloom Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1.7 Star-Tree Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.2 Choisir le bon index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
7.3 Star-Tree en détail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
7.4 Exemple de conguration d'index . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

8 Ingestion batch et temps réel 23


8.1 Ingestion batch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.2 Ingestion temps réel via Kafka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.3 Ingestion hybride . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.4 Upsert et déduplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

9 Intégration Apache Pinot avec Spring Boot 25


9.1 Architecture applicative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
9.2 Dépendances Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
9.3 Entités JPA côté OLTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
9.4 Service Pinot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
9.5 Controllers REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
9.6 Conguration : [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

10 Docker Compose et déploiement 28


10.1 Stack de déploiement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
10.2 Fichier [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
10.3 Commandes utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

11 Scripts OLTP et OLAP complets 30


11.1 Script OLTP (Postgres) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
11.2 Jeu de données de démonstration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
11.3 Schéma Pinot (OLAP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
11.4 Table Pinot (OLAP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
11.5 Requêtes analytiques typiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

12 Performance et observabilité 33
12.1 Métriques clés à surveiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
12.2 Intégration Prometheus / Grafana . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
12.3 Optimisation des requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
12.4 Dashboard Grafana recommandé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
12.5 Tuning des serveurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

Cours OLAP temps réel 2


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

13 Sécurité 35
13.1 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
13.2 Autorisation au niveau table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
13.3 Chirement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
13.4 Bonnes pratiques côté Spring Boot . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

14 Architecture Kafka + Pinot 36


14.1 Pourquoi Kafka avec Pinot ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
14.2 Topologie de bout en bout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
14.3 Conguration d'un producteur Spring Boot vers Kafka . . . . . . . . . . . . . . . . 36
14.4 Conguration Pinot REALTIME pour Kafka . . . . . . . . . . . . . . . . . . . . . 37
14.5 Débits et sizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
14.6 Tolérance aux pannes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

15 Observabilité et monitoring avancés 38


15.1 La  pyramide  de l'observabilité . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
15.2 Logs structurés côté Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
15.3 Tracing distribué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
15.4 Alerting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

16 Cas d'étude et exercices 40


16.1 Cas d'étude : tableau de bord e-commerce . . . . . . . . . . . . . . . . . . . . . . . 40
16.2 TP 1 : mise en place de la stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
16.3 TP 2 : ingestion des données dans Pinot . . . . . . . . . . . . . . . . . . . . . . . . 40
16.4 TP 3 : API d'analytics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
16.5 TP 4 : ingestion temps réel Kafka . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
16.6 Questions de révision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
16.7 Éléments de correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

17 Multi-Stage Query Engine 43


17.1 Limites du moteur historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
17.2 Le Multi-Stage Engine (v2+) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
17.3 Activer le Multi-Stage Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
17.4 Flux d'exécution multi-stage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
17.5 Cas d'usage du Multi-Stage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

18 Patterns d'architecture avec Pinot 45


18.1 Pattern 1 : Lambda Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
18.2 Pattern 2 : CQRS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
18.3 Pattern 3 : Event Sourcing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
18.4 Pattern 4 : Funnel Analytics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

19 Conclusion 47
19.1 Pour aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
19.2 Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

20 Glossaire 48
21 Bibliographie et ressources 50
21.1 Livres de référence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
21.2 Documentation ocielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
21.3 Articles et conférences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
21.4 Communauté . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

Cours OLAP temps réel 3


Chapitre 1

Introduction à Apache Pinot

1.1 Contexte : l'explosion des données analytiques


Depuis deux décennies, le paysage informatique a été marqué par une croissance exponentielle
des volumes de données : logs applicatifs, événements métier, capteurs IoT, interactions utilisateurs.
Les entreprises ne cherchent plus seulement à stocker ces données mais à les exploiter en temps réel
pour prendre des décisions quasi immédiates.
Les bases relationnelles classiques (Postgres, MySQL, Oracle) sont excellentes pour les trai-
tements transactionnels (OLTP), mais deviennent vite un goulot d'étranglement lorsqu'il s'agit
d'exécuter des requêtes analytiques de type agrégation multi-critères sur des milliards de lignes
en quelques millisecondes.
C'est précisément dans ce contexte qu'émergent les bases OLAP temps réel comme Apache
Pinot, Apache Druid ou ClickHouse.

1.2 Qu'est-ce qu'Apache Pinot ?


Dénition
Apache Pinot est une base de données OLAP distribuée conçue pour orir des requêtes
analytiques à faible latence (millisecondes) sur de gros volumes de données, en temps réel
et en batch.

Apache Pinot a été créé originellement par LinkedIn en 2013, puis donné à la fondation Apache
en 2018. Il est aujourd'hui utilisé par des entreprises telles que Uber, Walmart, Stripe et Slack
pour alimenter leurs tableaux de bord utilisateurs et internes en temps réel. Pinot a été conçu
dès le départ pour supporter des workloads critiques où la latence p99 doit rester inférieure à 100
millisecondes, même avec des milliards de lignes ingérées quotidiennement.

1.3 Historique et évolution


ˆ 2013 : projet interne chez LinkedIn pour alimenter le tableau de bord  Who Viewed My
Prole .
ˆ 2015 : open source sous licence Apache 2.0.
ˆ 2018 : donation à la fondation Apache, incubation.
ˆ 2021 : Pinot devient un Top-Level Project de la fondation Apache.
ˆ 2022 : sortie de la version 0.10 avec le Multi-Stage Query Engine supportant les jointures.
ˆ 20232024 : montée en puissance de l'intégration cloud (Kubernetes, déploiement managé
via StarTree).

4
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

1.4 Positionnement d'Apache Pinot


Ingestion Stockage Indexation Requêtes
temps réel colonnaire multiple SQL

1.5 Caractéristiques clés


ˆ Stockage colonnaire : optimisation pour les agrégations et les scans.
ˆ Indexation avancée : Inverted, Sorted, Range, Bloom, Star-Tree.
ˆ Ingestion hybride : batch (HDFS, S3) et temps réel (Kafka, Pulsar, Kinesis).
ˆ Haute disponibilité : architecture distribuée avec Zookeeper.
ˆ Requêtes SQL : compatibilité par le biais de Pinot-QL.
ˆ Scalabilité linéaire : ajout de serveurs sans interruption de service.
ˆ Multi-tenant : isolation logique entre équipes ou clients.

1.6 Cas d'usage industriels

Entreprise Cas d'usage Volumétrie


LinkedIn Prol, pubs, feed > 250 Mds événements/jour
Uber UberEats analytics temps réel > 10 Go/sec d'ingestion
Stripe Tableaux de bord marchands Milliards de transactions
Walmart Analytique e-commerce Scaling saisonnier Black Friday
Slack Analytique canaux et utilisateurs Requêtes p99 < 100 ms

Table 1.1  Exemples d'entreprises utilisant Apache Pinot en production

1.7 Comparaison avec les alternatives

Critère Apache Pinot Apache Druid ClickHouse


Latence Très faible Faible Faible
Ingestion temps réel Excellente (Kafka) Excellente Bonne
Support SQL Pinot-QL + multi-stage SQL Complet
Joins distribuées Oui (v1.0+) Limité Oui
Star-Tree index Oui (unique) Non Non
Écosystème Apache, StarTree Apache, Imply Yandex, Altinity

Table 1.2  Comparaison des moteurs OLAP temps réel

Astuce pratique
Pinot n'est pas un remplaçant d'une base OLTP. Il est complémentaire : Postgres gère les
transactions, Pinot sert les tableaux de bord analytiques.

Cours OLAP temps réel 5


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

1.8 Écosystème Apache Pinot


Apache Pinot s'inscrit dans un écosystème riche autour du traitement analytique :
ˆ Apache Kafka : bus de messages pour l'ingestion temps réel.
ˆ Apache Zookeeper : coordination du cluster.
ˆ Apache Helix : gestion des états du cluster.
ˆ Superset / Grafana : visualisation des résultats.
ˆ Trino / Presto : moteur SQL fédéré compatible Pinot.

Cours OLAP temps réel 6


Chapitre 2

OLTP vs OLAP : comparaison approfon-

die

2.1 Dénitions fondamentales


OLTP (Online Transaction Processing)
Système orienté transactions opérationnelles : INSERT, UPDATE, DELETE. Données nor-
malisées, très grande volumétrie d'opérations courtes.

OLAP (Online Analytical Processing)


Système orienté analyse : requêtes d'agrégation, tableaux de bord, statistiques. Données
dénormalisées (schéma en étoile ou ocon).

Ces deux paradigmes ont été formalisés par E. F. Codd dans les années 1990 pour distinguer
deux natures radicalement diérentes de traitement sur les données. L'OLTP vise la cohérence
transactionnelle (ACID), tandis que l'OLAP vise la performance sur les requêtes analytiques.

2.2 Architecture OLTP

Système OLTP  transactions courtes

U1

Spring Boot Service Postgres


U2
Controller métier OLTP
CRUD JDBC / JPA

U3

Figure 2.1  Architecture d'un système OLTP avec Spring Boot et Postgres

7
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

2.3 Architecture OLAP avec Pinot

Cluster Apache Pinot


Postgres
OLTP Pinot
Controller Spring Boot
API
Pinot
Kafka ETL Broker
stream mapping
Pinot Dashboard
Server UI

Fichiers
CSV / S3 Zookeeper

Figure 2.2  Architecture OLAP temps réel avec Apache Pinot

2.4 Tableau comparatif OLTP vs OLAP

Critère OLTP OLAP


Objectif Opérations métier Analyse et reporting
Opérations INSERT / UPDATE / DELETE SELECT avec agrégations
Schéma Normalisé (3NF) Dénormalisé (étoile)
Volume Go To / Po
Latence écriture Millisecondes (tx) Diérée (ETL) ou temps réel
Latence lecture Millisecondes Millisecondes (Pinot)
Outil exemple Postgres, MySQL Apache Pinot, ClickHouse
Indexation B-Tree, Hash Inverted, Star-Tree
Cohérence ACID forte Eventuelle (BASE)
Utilisateurs Opérationnels Analystes, dirigeants

Table 2.1  Comparaison OLTP / OLAP

2.5 Modélisation dimensionnelle


L'approche dimensionnelle popularisée par Ralph Kimball repose sur deux concepts fonda-
mentaux :
ˆ Les tables de faits contiennent les mesures quantitatives (CA, quantités, durée) et les clés
étrangères vers les dimensions.
ˆ Les tables de dimensions décrivent le contexte (qui, quoi, où, quand, comment).
Cette approche s'oppose à celle de Bill Inmon qui préconise un entrepôt central normalisé
(3NF) alimentant des data marts dimensionnels.

Cours OLAP temps réel 8


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

Astuce pratique
Pinot n'impose pas de schéma dimensionnel stricto sensu, mais il s'en inspire fortement : on
charge typiquement dans Pinot le résultat d'une jointure faits + dimensions pré-calculée,
sous forme d'une grande table aplatie.

Cours OLAP temps réel 9


Chapitre 3

Schéma relationnel OLTP

3.1 Principes de la modélisation relationnelle


Le modèle relationnel de Codd (1970) repose sur les principes suivants :
ˆ Les données sont organisées en relations (tables).
ˆ Chaque ligne est identiée de manière unique par une clé primaire.
ˆ Les relations entre tables sont matérialisées par des clés étrangères.
ˆ La normalisation (1NF, 2NF, 3NF, BCNF) élimine la redondance et les anomalies.

3.2 Modèle métier : e-commerce


Notre cas d'étude est une boutique en ligne vendant des produits. Les entités métier sont :
ˆ Customer : client ayant créé un compte.
ˆ Address : adresse de livraison d'un client (plusieurs possibles).
ˆ Category : catégorie produit.
ˆ Product : article vendu.
ˆ Order : commande passée par un client.
ˆ OrderItem : ligne de commande (produit + quantité).

3.3 Schéma relationnel


Le schéma ci-dessous présente la structure en 3NF sans chevauchement. Les èches représentent
les clés étrangères (FK).

10
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

CUSTOMERS CATEGORIES
PK id : BIGINT PK id : BIGINT
name : VARCHAR(100) name : VARCHAR(80)
email : VARCHAR(150) description : TEXT
country : VAR-
CHAR(50)
1..N
created_at : TIMES-
TAMP
PRODUCTS
1..N
PK id : BIGINT
ADDRESSES name : VARCHAR(100)
PK id : BIGINT ORDER_ITEMS
FK category_id
FK customer_id PK id : BIGINT price : NUMERIC(10,2)
street : VARCHAR(150) FK order_id
stock : INT
1..N FK product_id
city : VARCHAR(80) 1..N
zip : VARCHAR(10) quantity : INT
unit_price : NUME-
RIC(10,2)

1..N

ORDERS
PK id : BIGINT
FK customer_id
status : INT
total : NUMERIC(10,2)
created_at : TIMES-
TAMP

Figure 3.1  Schéma relationnel OLTP en 3NF

3.4 Script DDL Postgres complet


1 CREATE TABLE customers (
2 id BIGSERIAL PRIMARY KEY ,
3 name VARCHAR (100) NOT NULL ,
4 email VARCHAR (150) UNIQUE ,
5 country VARCHAR (50) ,
6 created_at TIMESTAMP DEFAULT NOW ()
7 );
8
9 CREATE TABLE addresses (
10 id BIGSERIAL PRIMARY KEY ,
11 customer_id BIGINT REFERENCES customers ( id ) ON DELETE CASCADE ,
12 street VARCHAR (150) ,
13 city VARCHAR (80) ,
14 zip VARCHAR (10)
15 );
16
17 CREATE TABLE categories (
18 id BIGSERIAL PRIMARY KEY ,
19 name VARCHAR (80) UNIQUE NOT NULL ,
20 description TEXT
21 );
22
23 CREATE TABLE products (

Cours OLAP temps réel 11


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

24 id BIGSERIAL PRIMARY KEY ,


25 name VARCHAR (100) NOT NULL ,
26 category_id BIGINT REFERENCES categories ( id ) ,
27 price NUMERIC (10 ,2) CHECK ( price >= 0) ,
28 stock INT DEFAULT 0
29 );
30
31 CREATE TABLE orders (
32 id BIGSERIAL PRIMARY KEY ,
33 customer_id BIGINT REFERENCES customers ( id ) ,
34 status INT DEFAULT 0 ,
35 total NUMERIC (10 ,2) ,
36 created_at TIMESTAMP DEFAULT NOW ()
37 );
38
39 CREATE TABLE order_items (
40 id BIGSERIAL PRIMARY KEY ,
41 order_id BIGINT REFERENCES orders ( id ) ON DELETE CASCADE ,
42 product_id BIGINT REFERENCES products ( id ) ,
43 quantity INT CHECK ( quantity > 0) ,
44 unit_price NUMERIC (10 ,2)
45 );
46
47 -- Index OLTP pour la performance
48 CREATE INDEX idx_orders_customer ON orders ( customer_id );
49 CREATE INDEX idx_orders_created ON orders ( created_at ) ;
50 CREATE INDEX idx_items_order ON order_items ( order_id ) ;
51 CREATE INDEX idx_items_product ON order_items ( product_id ) ;

Listing 3.1  Script DDL complet OLTP

3.5 Contraintes d'intégrité


ˆ Intégrité d'entité : PRIMARY KEY sur chaque table.
ˆ Intégrité référentielle : FOREIGN KEY sur customer_id, product_id, etc.
ˆ Intégrité de domaine : CHECK (price >= 0), CHECK (quantity > 0).
ˆ Unicité : UNIQUE(email), UNIQUE([Link]).

Attention
Dans un contexte analytique Pinot, ces contraintes ne seront plus appliquées : la cible OLAP
est dénormalisée et les erreurs doivent être détectées en amont (ETL ou source OLTP).

Cours OLAP temps réel 12


Chapitre 4

Data Warehouse et schéma en étoile

4.1 Pourquoi un Data Warehouse ?


Un Data Warehouse (entrepôt de données) centralise les données historiques issues de plu-
sieurs systèmes sources pour permettre l'analyse. Les caractéristiques d'un DW selon Inmon sont :
ˆ Orienté sujet : organisé autour des axes métier (ventes, clients, produits).
ˆ Intégré : données homogénéisées, formats uniformes.
ˆ Historisé : conservation de l'historique, pas de mise à jour destructive.
ˆ Non volatile : chargement en masse, lecture seule par les analystes.

4.2 Schéma en étoile (Star Schema)


Le schéma en étoile est la forme la plus courante en Business Intelligence. Il comprend :
ˆ Une table centrale de faits contenant les mesures numériques et les clés étrangères vers les
dimensions.
ˆ Des tables de dimensions autour, décrivant le contexte.

13
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

4.3 Schéma DW en étoile

DIM_DATE

DIM_CUSTOMER DIM_GEOGRAPHY
PK date_sk
full_date
PK customer_sk year / month / day PK geo_sk
customer_id weekday country
name region
email city
FACT_SALES

PK sale_id
FK customer_sk
FK product_sk
FK date_sk
FK geo_sk
FK status_sk

amount : DOUBLE
quantity : INT
discount : DOUBLE
DIM_PRODUCT
DIM_CHANNEL

PK product_sk DIM_STATUS
PK channel_sk
product_id
type
name
PK status_sk source
category
code
label

Figure 4.1  Schéma en étoile du Data Warehouse e-commerce

4.4 Table de faits : détail

Colonne Type Description


sale_id LONG Identiant unique de la ligne de fait
customer_sk LONG Clé surrogate vers DIM_CUSTOMER
product_sk LONG Clé surrogate vers DIM_PRODUCT
date_sk LONG Clé surrogate vers DIM_DATE
geo_sk LONG Clé surrogate vers DIM_GEOGRAPHY
status_sk LONG Clé surrogate vers DIM_STATUS
amount DOUBLE Mesure additive : montant
quantity INT Mesure additive : quantité
discount DOUBLE Mesure semi-additive : remise

Table 4.1  Structure de la table de faits FACT_SALES

4.5 Typologie des dimensions


ˆ Dimension conforme : partagée entre plusieurs faits (ex. DIM_DATE).

Cours OLAP temps réel 14


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

ˆ Dimension dégénérée : clé technique sans description (ex. numéro de facture).


ˆ Dimension junk : agrégation de ags et statuts peu utilisés.
ˆ Role-playing : même dimension utilisée avec plusieurs rôles (DIM_DATE comme date de
commande ET date de livraison).

4.6 SCD : Slowly Changing Dimensions


Les dimensions évoluent dans le temps. Kimball propose plusieurs stratégies :
ˆ SCD Type 0 : gé, pas de mise à jour.
ˆ SCD Type 1 : écrasement pur (perte de l'historique).
ˆ SCD Type 2 : ajout d'une nouvelle ligne avec valid_from, valid_to, is_current.
ˆ SCD Type 3 : colonnes historiques (previous_value, current_value).

Astuce pratique
Dans Pinot, on privilégie le SCD Type 2 car on peut facilement ltrer les lignes actives via
WHERE is_current = true.

4.7 Schéma en ocon vs étoile


Le schéma en ocon (snowake ) décompose les dimensions en sous-dimensions normalisées.
Exemple : DIM_PRODUCT → DIM_CATEGORY → DIM_DEPARTMENT.
ˆ Avantage : économie d'espace, cohérence renforcée.
ˆ Inconvénient : plus de jointures, performance dégradée.
Pour Pinot, le schéma en étoile aplati (at) est le plus adapté : pas de jointure nécessaire
à l'exécution.

4.8 Schéma en ocon

DIM_GEO DIM_CUSTOMER DIM_DATE DIM_MONTH


PK customer_sk PK date_sk PK month_sk
PK geo_sk
customer_id full_date month_name
country, region
FK geo_sk FK month_sk FK year_sk

FACT_SALES
DIM_DEPT PK sale_id

FK customer_sk
DIM_YEAR
PK dept_sk PK year_sk
FK product_sk
dept_name year_value
FK date_sk

amount, quantity

DIM_CATEGORY DIM_PRODUCT
PK category_sk PK product_sk

name name

FK dept_sk FK category_sk

Figure 4.2  Schéma en ocon (snowake) : dimensions normalisées

Cours OLAP temps réel 15


Attention
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY
Le schéma en ocon est déconseillé pour Pinot : chaque niveau supplémentaire implique
une jointure, ce qui dégrade la latence. Dans Pinot on préfère le schéma en étoile aplati (at
star).

Cours OLAP temps réel 16


Chapitre 5

Conception ETL et mapping

5.1 Diagramme du pipeline ETL

Extract Transform Load


(Postgres / CSV) (mapping) (Pinot)

Source OLTP Logique métier Cible OLAP

Figure 5.1  Pipeline ETL Extract-Transform-Load

5.2 Extract : les sources


ˆ Connexion JDBC : lecture directe de Postgres.
ˆ Fichiers plats : CSV, Parquet sur S3/HDFS.
ˆ Kafka : ux temps réel d'événements.
ˆ API REST : appels HTTP vers des systèmes tiers.

5.3 Transform : les règles de transformation


ˆ Nettoyage : suppression des valeurs nulles, déduplication.
ˆ Normalisation : UPPER(), TRIM(), formats ISO.
ˆ Enrichissement : jointures avec les dimensions.
ˆ Agrégation : pré-calcul de sommes par jour/heure.
ˆ Dérivation : calcul de colonnes (year, month, quarter).

5.4 Load : les stratégies


ˆ Full load : rechargement complet de la table.
ˆ Incrémental : chargement des seuls nouveaux enregistrements (par date).
ˆ Upsert : mise à jour d'enregistrements existants (Pinot supporte l'upsert sur les tables REAL-
TIME).

17
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

5.5 Table de mapping ETL

Source (OLTP) Cible (Pinot) Transformation Type


[Link] order_id Copie directe LONG
orders.customer_id customer_id Copie directe LONG
[Link] amount Cast numeric → double DOUBLE
orders.created_at event_time Timestamp → epoch ms LONG
[Link] country Join + UPPER() STRING
[Link] category Join + normalisation STRING
[Link] status Mapping : 0→paid, 1→pending STRING
 year Derived : YEAR(created_at) INT
 month Derived : MONTH(created_at) INT
 weekday Derived : DAYOFWEEK(created_at) INT

Table 5.1  Mapping ETL de Postgres vers Apache Pinot

Attention
Pinot ne supporte pas les JOINs entre tables par défaut (hors Lookup et Multi-Stage Engine ).
Le schéma doit donc être dénormalisé au moment du chargement.

5.6 Orchestration du pipeline


Pour orchestrer un ETL vers Pinot, plusieurs outils sont possibles :
ˆ Apache Airow : DAG Python pour la planication.
ˆ Apache NiFi : orchestration visuelle data ow.
ˆ Spring Batch : dans l'écosystème Spring Boot.
ˆ Kafka Connect + Pinot Sink : streaming natif.

Cours OLAP temps réel 18


Chapitre 6

Architecture interne d'Apache Pinot

6.1 Les composants du cluster


Un cluster Pinot est composé de cinq briques principales :
ˆ Controller : coordinateur du cluster, API REST d'administration.
ˆ Broker : reçoit les requêtes SQL, les découpe en sous-requêtes, agrège les résultats.
ˆ Server : stocke les segments, exécute les requêtes localement.
ˆ Minion (optionnel) : tâches de maintenance en arrière-plan (compaction, rebuild d'index).
ˆ Zookeeper : stocke les métadonnées (tables, schémas, états).

6.2 Segments : unité de stockage


Un segment est un chier immutable contenant un bloc de données. Toute la logique de Pinot
tourne autour de ce concept.
ˆ Un segment contient généralement quelques millions de lignes.
ˆ Il est compressé colonne par colonne.
ˆ Il est répliqué sur plusieurs serveurs (facteur de réplication).
ˆ Il est identié par un nom unique : orders_olap_OFFLINE_0, etc.

6.3 Tables OFFLINE, REALTIME, HYBRID

Type Source Cas d'usage


OFFLINE Batch (HDFS, S3, local) Historique, reporting
REALTIME Kafka, Pulsar, Kinesis Streaming, métriques vivantes
HYBRID Combinaison des deux Fusion historique + temps réel

Table 6.1  Types de tables Apache Pinot

6.4 Tenants et isolation


Un tenant est un groupe logique de serveurs. Il permet d'isoler des workloads :
ˆ Broker tenant : groupe de brokers dédiés.
ˆ Server tenant OFFLINE / REALTIME : serveurs spécialisés.

19
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

6.5 Cycle de vie d'un segment

CREATING CONSUMING ONLINE OFFLINE DELETED


init ush retention purge

Figure 6.1  Cycle de vie d'un segment Pinot (REALTIME)

6.6 Flux d'une requête SQL

Server 1

4. Résultat
1. SQL
Client JDBC Broker Server 2

Server 3

2. Sous-requêtes parallélisées / 3. Agrégation partielle

Figure 6.2  Flux d'exécution d'une requête SQL distribuée dans Pinot

Cours OLAP temps réel 20


Chapitre 7

Indexation avancée

7.1 Les types d'index Pinot


La force de Pinot réside dans la diversité de ses index.

7.1.1 Forward Index

Index par défaut : stocke les valeurs ligne par ligne pour chaque colonne. Accès rapide par
position.

7.1.2 Dictionary Encoding

Chaque valeur distincte est codée par un entier. Diminue drastiquement la taille pour les co-
lonnes à faible cardinalité.

7.1.3 Inverted Index

Map : valeur → liste des positions. Très ecace pour les ltres WHERE country = 'France'.

7.1.4 Sorted Index

Les lignes sont triées sur une colonne. Permet un accès par dichotomie et un stockage RLE
(run-length encoding) compact.

7.1.5 Range Index

Accélère les ltres BETWEEN x AND y sur les colonnes numériques.

7.1.6 Bloom Filter

Structure probabiliste : accélère les ltres = valeur sur les colonnes à haute cardinalité.

7.1.7 Star-Tree Index

Pré-agrégation multi-dimensionnelle stockée dans une arborescence. Permet de répondre à des


requêtes d'agrégation en O(log n) au lieu de O(n).

21
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

7.2 Choisir le bon index

Index Idéal pour À éviter si


Inverted Filtres d'égalité, cardinalité moyenne Cardinalité très élevée
Sorted Colonne monotone (time, id) Données réellement aléatoires
Range Filtres BETWEEN sur métrique Colonne catégorielle
Bloom Lookups ponctuels Range queries
Star-Tree GROUP BY fréquents Requêtes totalement ad-hoc

Table 7.1  Guide de choix d'index dans Apache Pinot

7.3 Star-Tree en détail


Le Star-Tree est une structure arborescente où chaque niveau représente une dimension de
dimensionsSplitOrder. Les feuilles contiennent des lignes pré-agrégées. Lors d'une requête GROUP
BY, Pinot choisit le n÷ud le plus bas compatible et évite de scanner les lignes individuelles.

Root (ALL)

country=FR country=DE country=MA

cat=Elec cat=Sport cat=Elec cat=Groc

Figure 7.1  Exemple de Star-Tree sur (country, category)

7.4 Exemple de conguration d'index


1 " tableIndexConfig " : {
2 " invertedIndexColumns " : [ " country " , " category " , " status " ] ,
3 " rangeIndexColumns " : [ " amount " ] ,
4 " sortedColumn " : [ " event_time " ] ,
5 " bloomFilterColumns " : [ " customer_id " ] ,
6 " starTreeIndexConfigs " : [
7 {
8 " dimensionsSplitOrder ": [ " country " , " category " ] ,
9 " functionColumnPairs " : [ " SUM__amount " , " COUNT__ * " ] ,
10 " maxLeafRecords " : 10000
11 }
12 ]
13 }

Listing 7.1  Extrait du table cong Pinot

Cours OLAP temps réel 22


Chapitre 8

Ingestion batch et temps réel

8.1 Ingestion batch


L'ingestion batch permet de charger de gros volumes historiques depuis :
ˆ Fichiers locaux : CSV, JSON, Avro, Parquet, ORC.
ˆ HDFS, S3, Azure Blob, GCS.
Le pipeline typique est décrit dans un chier YAML ingestion_spec.yaml. Pinot génère alors
des segments et les pousse sur le controller via SegmentTarPushJobRunner.

8.2 Ingestion temps réel via Kafka


1 " tableType " : " REALTIME " ,
2 " segmentsConfig " : {
3 " timeColumnName " : " event_time " ,
4 " schemaName " : " orders_olap " ,
5 " replication ": " 1 "
6 },
7 " streamConfigs " : {
8 " streamType " : " kafka " ,
9 " stream . kafka . topic . name " : " orders " ,
10 " stream . kafka . broker . list " : " kafka :9092 " ,
11 " stream . kafka . consumer . factory . class . name " :
12 " org . apache . pinot . plugin . stream . kafka20 . KafkaConsumerFactory " ,
13 " stream . kafka . decoder . class . name " :
14 " org . apache . pinot . plugin . stream . kafka . KafkaJSONMessageDecoder " ,
15 " realtime . segment . flush . threshold . rows " : " 100000 " ,
16 " realtime . segment . flush . threshold . time " : " 3600000 "
17 }

Listing 8.1  Stream cong Kafka pour Pinot REALTIME

8.3 Ingestion hybride


Une même table logique peut être alimentée simultanément en OFFLINE (historique) et REAL-
TIME (streaming). Pinot fusionne automatiquement les résultats à la lecture.

8.4 Upsert et déduplication


Depuis la v0.8, Pinot supporte l'upsert sur les tables REALTIME :

23
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

1 " upsertConfig " : {


2 " mode " : " FULL " ,
3 " primaryKeyColumn " : " order_id "
4 }

Listing 8.2  Conguration upsert

Cours OLAP temps réel 24


Chapitre 9

Intégration Apache Pinot avec Spring Boot

9.1 Architecture applicative

Couche Controller (REST API)

Couche Service (logique métier)

Couche Repository (accès données)

Client Apache Pinot (JDBC)

Postgres (JPA / Hibernate)

Figure 9.1  Architecture en couches Spring Boot + Pinot + Postgres

9.2 Dépendances Maven


1 < dependency >
2 < groupId > org . springframework . boot </ groupId >
3 < artifactId > spring - boot - starter - web </ artifactId >
4 </ dependency >
5 < dependency >
6 < groupId > org . springframework . boot </ groupId >
7 < artifactId > spring - boot - starter - data - jpa </ artifactId >
8 </ dependency >
9 < dependency >
10 < groupId > org . postgresql </ groupId >
11 < artifactId > postgresql </ artifactId >
12 </ dependency >
13 < dependency >
14 < groupId > org . apache . pinot </ groupId >

25
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

15 < artifactId > pinot - java - client </ artifactId >


16 < version > 1.0.0 </ version >
17 </ dependency >

Listing 9.1  Extrait du [Link]

9.3 Entités JPA côté OLTP


1 @Entity
2 @Table ( name = " orders " )
3 @Getter @Setter @NoArgsConstructor
4 public class Order {
5 @Id
6 @GeneratedValue ( strategy = GenerationType . IDENTITY )
7 private Long id ;
8
9 @Column ( name = " customer_id " )
10 private Long customerId ;
11
12 @Column ( name = " product_id " )
13 private Long productId ;
14
15 @Column ( precision = 10 , scale = 2)
16 private BigDecimal amount ;
17
18 private Integer status = 0;
19
20 @Column ( name = " created_at " )
21 private LocalDateTime createdAt = LocalDateTime . now () ;
22 }

Listing 9.2  Entité Order

9.4 Service Pinot


1 @Service
2 public class PinotAnalyticsService {
3
4 @Value ( " $ { pinot . broker . url : pinot - broker :8099} " )
5 private String brokerUrl ;
6
7 private Connection connection ;
8
9 @PostConstruct
10 public void init () {
11 this . connection = ConnectionFactory . fromHostList ( brokerUrl ) ;
12 }
13
14 public List < Map < String , Object > > topCountriesByRevenue ( int limit ) {
15 String query = " SELECT country , SUM ( amount ) AS ca " +
16 " FROM orders_olap GROUP BY country " +
17 " ORDER BY ca DESC LIMIT " + limit ;
18 return execute ( query ) ;
19 }
20 // ...
21 }

Listing 9.3  Service de requête Pinot en Spring Boot

Cours OLAP temps réel 26


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

9.5 Controllers REST


1 @RestController
2 @RequestMapping ( " / api / analytics " )
3 @RequiredArgsConstructor
4 public class AnalyticsController {
5 private final PinotAnalyticsService analyticsService ;
6
7 @GetMapping ( " / top - countries " )
8 public List < Map < String , Object > > topCountries (
9 @RequestParam ( defaultValue = " 10 " ) int limit ) {
10 return analyticsService . topCountriesByRevenue ( limit ) ;
11 }
12 }

Listing 9.4  AnalyticsController

9.6 Conguration : [Link]


1 spring :
2 datasource :
3 url : jdbc : postgresql : // postgres :5432/ pinotdb
4 username : pinotuser
5 password : pinotpass
6 jpa :
7 hibernate . ddl - auto : update
8
9 pinot :
10 broker :
11 url : pinot - broker :8099
12 controller :
13 url : http : // pinot - controller :9000

Listing 9.5  [Link]

Astuce pratique
La URL pinot-broker:8099 est un nom DNS résolu par Docker dans le réseau pinot-net.
En local hors conteneur, remplacer par localhost:8099.

Cours OLAP temps réel 27


Chapitre 10

Docker Compose et déploiement

10.1 Stack de déploiement

Spring Boot Postgres Zookeeper


:8080 :5432 :2181

Pinot Ctrl Pinot Broker Pinot Server


:9000 :8099 :7050

Réseau Docker : pinot-net

Figure 10.1  Topologie Docker Compose

10.2 Fichier [Link]


1 services :
2 postgres :
3 image : postgres :16 - alpine
4 environment :
5 POSTGRES_DB : pinotdb
6 POSTGRES_USER : pinotuser
7 POSTGRES_PASSWORD : pinotpass
8 ports : [ " 5432:5432 " ]
9 networks : [ pinot - net ]
10
11 zookeeper :
12 image : zookeeper :3.9
13 networks : [ pinot - net ]
14
15 pinot - controller :
16 image : apachepinot / pinot :1.0.0
17 command : " StartController - zkAddress zookeeper :2181 "
18 ports : [ " 9000:9000 " ]
19 depends_on : [ zookeeper ]
20 networks : [ pinot - net ]
21
22 pinot - broker :
23 image : apachepinot / pinot :1.0.0
24 command : " StartBroker - zkAddress zookeeper :2181 "
25 ports : [ " 8099:8099 " ]
26 depends_on : [ pinot - controller ]

28
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

27 networks : [ pinot - net ]


28
29 pinot - server :
30 image : apachepinot / pinot :1.0.0
31 command : " StartServer - zkAddress zookeeper :2181 "
32 depends_on : [ pinot - broker ]
33 networks : [ pinot - net ]
34
35 spring - app :
36 build : .
37 ports : [ " 8080:8080 " ]
38 depends_on : [ postgres , pinot - broker ]
39 networks : [ pinot - net ]

Listing 10.1  Extrait du [Link]

10.3 Commandes utiles


1 # Demarrer toute la stack
2 docker compose up -d -- build
3
4 # Verifier l ' etat
5 docker compose ps
6
7 # Suivre les logs de l ' application Spring Boot
8 docker compose logs -f spring - app
9
10 # Arreter et nettoyer ( volumes inclus )
11 docker compose down -v

Listing 10.2  Commandes Docker Compose

Astuce pratique
Le chier [Link] fourni dans le projet permet de lancer toute la stack avec
une seule commande : docker compose up -d.

Cours OLAP temps réel 29


Chapitre 11

Scripts OLTP et OLAP complets

11.1 Script OLTP (Postgres)


1 CREATE TABLE customers (
2 id BIGSERIAL PRIMARY KEY ,
3 name VARCHAR (100) NOT NULL ,
4 country VARCHAR (50) ,
5 created_at TIMESTAMP DEFAULT NOW ()
6 );
7
8 CREATE TABLE products (
9 id BIGSERIAL PRIMARY KEY ,
10 name VARCHAR (100) NOT NULL ,
11 category VARCHAR (50) ,
12 price NUMERIC (10 ,2)
13 );
14
15 CREATE TABLE orders (
16 id BIGSERIAL PRIMARY KEY ,
17 customer_id BIGINT REFERENCES customers ( id ) ,
18 product_id BIGINT REFERENCES products ( id ) ,
19 amount NUMERIC (10 ,2) ,
20 status INT DEFAULT 0 ,
21 created_at TIMESTAMP DEFAULT NOW ()
22 );

Listing 11.1  Création du schéma OLTP

11.2 Jeu de données de démonstration


1 INSERT INTO customers ( name , country ) VALUES
2 ( ' Alice Dupont ' , ' France ') ,
3 ( ' Bob Martin ' , ' France ') ,
4 ( ' Carlos Silva ' , ' Brazil ') ,
5 ( ' Hassan Tazi ' , ' Morocco ') ;
6
7 INSERT INTO products ( name , category , price ) VALUES
8 ( ' Laptop Pro 15 ' , ' Electronics ' , 1299.99) ,
9 ( ' Smartphone X ' , ' Electronics ' , 899.00) ,
10 ( ' Running Shoes ' , ' Sport ' , 120.50) ;
11
12 INSERT INTO orders ( customer_id , product_id , amount , status , created_at )
13 VALUES (1 , 1 , 1299.99 , 0 , NOW () - INTERVAL ' 10 days ') ;

Listing 11.2  Seed OLTP

30
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

11.3 Schéma Pinot (OLAP)


1 {
2 " schemaName " : " orders_olap " ,
3 " dimensionFieldSpecs " : [
4 { " name ": " order_id " , " dataType " : " LONG " } ,
5 { " name ": " customer_id " , " dataType " : " LONG " } ,
6 { " name ": " product_id " , " dataType " : " LONG " } ,
7 { " name ": " country " , " dataType " : " STRING " } ,
8 { " name ": " category " , " dataType " : " STRING " } ,
9 { " name ": " status " , " dataType " : " STRING " }
10 ],
11 " metricFieldSpecs " : [
12 { " name ": " amount " , " dataType " : " DOUBLE " }
13 ],
14 " dateTimeFieldSpecs " : [
15 {
16 " name " : " event_time " ,
17 " dataType " : " LONG " ,
18 " format " : " 1: MILLISECONDS : EPOCH " ,
19 " granularity " : " 1: MILLISECONDS "
20 }
21 ]
22 }

Listing 11.3  Schéma Pinot JSON

11.4 Table Pinot (OLAP)


1 {
2 " tableName " : " orders_olap " ,
3 " tableType " : " OFFLINE " ,
4 " segmentsConfig " : {
5 " timeColumnName " : " event_time " ,
6 " schemaName " : " orders_olap " ,
7 " replication " : " 1 "
8 },
9 " tenants " : {
10 " broker " : " DefaultTenant " ,
11 " server " : " DefaultTenant "
12 },
13 " tableIndexConfig " : {
14 " loadMode " : " MMAP " ,
15 " invertedIndexColumns " : [ " country " ," category " ," status " ] ,
16 " rangeIndexColumns " : [ " amount " ] ,
17 " sortedColumn " : [ " event_time " ] ,
18 " starTreeIndexConfigs " : [
19 {
20 " dimensionsSplitOrder " : [ " country " ," category " ] ,
21 " functionColumnPairs " : [ " SUM__amount " ," COUNT__ * " ] ,
22 " maxLeafRecords ": 10000
23 }
24 ]
25 }
26 }

Listing 11.4  Conguration de la table Pinot

11.5 Requêtes analytiques typiques

Cours OLAP temps réel 31


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

1 -- Top 10 pays par chiffre d ' affaires


2 SELECT country , SUM ( amount ) AS ca
3 FROM orders_olap
4 GROUP BY country
5 ORDER BY ca DESC
6 LIMIT 10;
7
8 -- Ventes par mois et par categorie
9 SELECT category ,
10 DATETIMECONVERT ( event_time ,
11 '1: MILLISECONDS : EPOCH ' ,
12 '1: DAYS : SIMPLE_DATE_FORMAT : yyyy - MM ' ,
13 '1: MONTHS ') AS month ,
14 COUNT (*) AS nb_orders
15 FROM orders_olap
16 GROUP BY category , month
17 ORDER BY month ;

Listing 11.5  Requêtes Pinot SQL

Cours OLAP temps réel 32


Chapitre 12

Performance et observabilité

12.1 Métriques clés à surveiller


ˆ Query latency : p50, p90, p99.
ˆ Ingestion lag : délai entre Kafka et Pinot.
ˆ Segment build time : temps de création d'un segment.
ˆ Heap / GC : JVM des serveurs Pinot.
ˆ Disk usage : croissance des segments.

12.2 Intégration Prometheus / Grafana


Pinot expose des métriques JMX qui peuvent être scrapées par un JMX Exporter et consommées
par Prometheus. Un dashboard Grafana ociel est disponible.

12.3 Optimisation des requêtes


ˆ Préférer un GROUP BY sur des colonnes indexées (Star-Tree).
ˆ Éviter LIKE '%xxx%' non anchored.
ˆ Utiliser LIMIT systématiquement.
ˆ Penser au pré-ltrage temporel via event_time.
ˆ Utiliser EXPLAIN PLAN FOR <query> pour comprendre l'exécution.
ˆ Éviter les sous-requêtes imbriquées non nécessaires.
ˆ Partitionner les tables REALTIME sur la clé primaire quand c'est possible.

33
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

12.4 Dashboard Grafana recommandé

Dashboard Grafana  Pinot monitoring

Latence p99
QPS Broker Lag Kafka
des requêtes

Heap JVM Erreurs


Taille segments
Server ingestion

Figure 12.1  Panneaux typiques d'un dashboard de monitoring Pinot

12.5 Tuning des serveurs


ˆ Heap JVM : xer -Xms = -Xmx pour éviter les redimensionnements.
ˆ GC : G1GC recommandé pour les serveurs Pinot, ZGC pour des workloads à très faible
latence.
ˆ Nombre de threads : ajuster [Link] selon les c÷urs
CPU.
ˆ Segment size : viser 100 à 500 Mo par segment.

Cours OLAP temps réel 34


Chapitre 13

Sécurité

13.1 Authentication
Pinot supporte plusieurs mécanismes :
ˆ Basic Auth (utilisateur / mot de passe).
ˆ OAuth 2.0 / OIDC (via plugin).
ˆ JWT côté broker.

13.2 Autorisation au niveau table


Des access control factories permettent de restreindre l'accès par table et par utilisateur.

13.3 Chirement
ˆ TLS pour les communications inter-composants.
ˆ Chirement des segments au repos (via le stockage).

13.4 Bonnes pratiques côté Spring Boot


ˆ Ne jamais concaténer directement les paramètres utilisateurs dans la requête SQL (risque
d'injection).
ˆ Valider et borner les paramètres (ex. @Max(100) sur le limit).
ˆ Utiliser Spring Security pour exposer l'API d'analytics.
ˆ Logger les requêtes longues via AOP pour l'auditabilité.

1 @GetMapping ( " / top - products " )


2 public List < Map < String , Object > > topProducts (
3 @RequestParam ( defaultValue = " 10 " )
4 @Min (1) @Max (100) int limit ) {
5 return analyticsService . topProducts ( limit ) ;
6 }

Listing 13.1  Validation des paramètres côté API

35
Chapitre 14

Architecture Kafka + Pinot

14.1 Pourquoi Kafka avec Pinot ?


Kafka est le bus de messages standard pour le streaming distribué. Sa combinaison avec Pinot
permet de :
ˆ Découpler producteurs et consommateurs.
ˆ Conserver un log durable des événements.
ˆ Autoriser plusieurs consommateurs (Pinot, Spark, analyse ML).
ˆ Ingérer en continu avec une latence de quelques secondes.

14.2 Topologie de bout en bout

Spring Boot Pinot


Producer REALTIME table

Kafka Dashboard
topic : orders Grafana
Debezium CDC

Postgres Spark
OLTP ML pipeline

Figure 14.1  Architecture événementielle Kafka + Pinot

14.3 Conguration d'un producteur Spring Boot vers Kafka


1 @Service
2 public class OrderEventProducer {
3
4 private final KafkaTemplate < String , String > kafkaTemplate ;
5 private final ObjectMapper mapper ;
6
7 public void publish ( Order order ) {
8 try {
9 String json = mapper . writeValueAsString ( order ) ;
10 kafkaTemplate . send ( " orders " , order . getId () . toString () , json ) ;
11 } catch ( Exception e ) {

36
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

12 throw new RuntimeException ( " Kafka publish failed " , e ) ;


13 }
14 }
15 }

Listing 14.1  Producteur Spring Boot

14.4 Conguration Pinot REALTIME pour Kafka


1 {
2 " tableName " : " orders_olap " ,
3 " tableType " : " REALTIME " ,
4 " streamConfigs " : {
5 " streamType " : " kafka " ,
6 " stream . kafka . topic . name " : " orders " ,
7 " stream . kafka . broker . list " : " kafka :9092 " ,
8 " stream . kafka . consumer . factory . class . name " :
9 " org . apache . pinot . plugin . stream . kafka20 . KafkaConsumerFactory " ,
10 " stream . kafka . decoder . class . name " :
11 " org . apache . pinot . plugin . stream . kafka . KafkaJSONMessageDecoder " ,
12 " realtime . segment . flush . threshold . rows " : " 100000 " ,
13 " realtime . segment . flush . threshold . time " : " 1 h "
14 }
15 }

Listing 14.2  Table REALTIME Kafka

14.5 Débits et sizing


Quelques ordres de grandeur industriels :
ˆ Un broker Kafka bien conguré : 100 Mo/s d'ingestion par instance.
ˆ Un serveur Pinot : quelques millions de lignes par seconde en ingestion REALTIME.
ˆ Scaling horizontal en ajoutant des partitions Kafka et des serveurs Pinot.

14.6 Tolérance aux pannes


ˆ Kafka : réplication inter-brokers ([Link] = 3).
ˆ Pinot : réplication au niveau segment.
ˆ Stockage profond : pousse périodique des segments sur S3/HDFS.

Cours OLAP temps réel 37


Chapitre 15

Observabilité et monitoring avancés

15.1 La  pyramide  de l'observabilité

Traces

Logs

Métriques

Figure 15.1  Pyramide classique de l'observabilité

15.2 Logs structurés côté Spring


1 < configuration >
2 < appender name = " JSON " class = " ch . qos . logback . core . ConsoleAppender " >
3 < encoder class = " net . logstash . logback . encoder . LogstashEncoder " / >
4 </ appender >
5 < root level = " INFO " >
6 < appender - ref ref = " JSON " / >
7 </ root >
8 </ configuration >

Listing 15.1  Logback JSON pour une ingestion Loki

15.3 Tracing distribué


Avec OpenTelemetry, chaque requête peut être suivie à travers les couches Spring → Pinot
→ Kafka. Le span d'une requête SQL inclut la latence côté broker et la latence côté server.

15.4 Alerting
ˆ Alerte : latence p99 > 500 ms pendant 5 minutes.

38
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

ˆ Alerte : lag Kafka > 30 s.


ˆ Alerte : taux d'erreur API > 1 %.

Cours OLAP temps réel 39


Chapitre 16

Cas d'étude et exercices

16.1 Cas d'étude : tableau de bord e-commerce


Un site e-commerce souhaite proposer à ses marchands un tableau de bord temps réel indiquant,
pour chaque vendeur :
ˆ Le chire d'aaires du jour.
ˆ Les 10 produits les plus vendus.
ˆ Le nombre de commandes en attente.
ˆ La répartition géographique des ventes.
Architecture cible : Postgres (source) → Kafka (événements) → Pinot (OLAP REALTIME)
→ Spring Boot API → Dashboard front.

16.2 TP 1 : mise en place de la stack


TP 1
Objectif : lancer la stack complète et vérier l'accès à Postgres et à Pinot.
1. Cloner le projet.
2. Lancer docker compose up -d build.
3. Vérier les endpoints : [Link] (Pinot), [Link]
(Spring).
4. Insérer un client via l'API Spring.

16.3 TP 2 : ingestion des données dans Pinot


TP 2
Objectif : charger dans Pinot le chier CSV exporté depuis Postgres.
1. Exporter orders_olap.csv.
2. Créer le schéma et la table Pinot.
3. Lancer l'ingestion batch.
4. Exécuter une requête SQL via la console.

40
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

16.4 TP 3 : API d'analytics


TP 3
Objectif : construire un nouvel endpoint /api/analytics/top-products.
1. Ajouter la méthode dans PinotAnalyticsService.
2. Exposer l'endpoint dans AnalyticsController.
3. Tester avec curl.

16.5 TP 4 : ingestion temps réel Kafka


TP 4 (approfondissement)
Objectif : ajouter Kafka au docker-compose et ingérer un ux d'événements dans Pinot.
1. Ajouter les services kafka et kafka-ui.
2. Créer un topic orders.
3. Modier la table Pinot en REALTIME.
4. Produire des messages JSON depuis Spring Boot.
5. Vérier l'ingestion quasi-immédiate.

16.6 Questions de révision


1. Quelles sont les cinq briques d'un cluster Pinot et leurs rôles ?
2. Quelle est la diérence entre un schéma en étoile et un schéma en ocon ?
3. Pourquoi Pinot n'est-il pas adapté à l'OLTP ?
4. Quels sont les cas d'usage typiques d'un index Star-Tree ?
5. Décrivez les étapes d'un pipeline ETL Postgres → Pinot.
6. Quelle stratégie SCD retenir lorsqu'on veut conserver l'historique d'une dimension ?
7. Quelle est la diérence entre une table OFFLINE, REALTIME et HYBRID ?
8. Pourquoi dénormalise-t-on le schéma avant de charger dans Pinot ?
9. Quel rôle joue Zookeeper dans le cluster ?
10. Comment Pinot répond-il à une requête GROUP BY en utilisant un Star-Tree ?

16.7 Éléments de correction


1. Composants : Controller (coordination), Broker (dispatch des requêtes), Server (stockage
et exécution), Minion (tâches de maintenance), Zookeeper (métadonnées et états).
2. Étoile vs ocon : l'étoile a des dimensions aplaties (une seule jointure), le ocon normalise
les dimensions (plusieurs niveaux).
3. OLTP inadapté : Pinot n'ore pas de transactions ACID, pas de mise à jour ligne à ligne
performante, pas de contraintes référentielles.
4. Star-Tree : pré-agrège les mesures selon un ordre de dimensions. Idéal pour des GROUP BY
récurrents avec SUM, COUNT, MIN, MAX.
5. ETL Postgres → Pinot : (1) EXTRACT via SQL, (2) TRANSFORM en CSV/Avro dé-
normalisé, (3) LOAD via LaunchDataIngestionJob ou Kafka.

Cours OLAP temps réel 41


Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

6. SCD Type 2 : ajoute une ligne à chaque évolution et gère valid_from/valid_to/is_current.


7. OFFLINE / REALTIME / HYBRID : batch, streaming, union des deux. HYBRID
permet l'historique profond + la fraîcheur temps réel.
8. Dénormalisation : Pinot scanne une seule table. La jointure au runtime serait coûteuse. On
la fait en amont (ETL) une seule fois.
9. Zookeeper : stocke les schémas, la table cong, la liste des segments et leur état, coordonne
les leaders.
10. Star-Tree + GROUP BY : Pinot descend dans l'arbre jusqu'au n÷ud pré-agrégé le plus
spécique couvrant le ltre, puis renvoie directement l'agrégat sans scanner les lignes de
détail.

Cours OLAP temps réel 42


Chapitre 17

Multi-Stage Query Engine

17.1 Limites du moteur historique


Le moteur de requête historique de Pinot (v2 engine) :
ˆ N'exécute les requêtes que sur une seule table.
ˆ Ne supporte pas les jointures shue entre tables distribuées.
ˆ Se limite aux agrégations sur la table scannée.

17.2 Le Multi-Stage Engine (v2+)


Introduit en 2022, il décompose une requête en plusieurs étapes (stages) exécutées en parallèle
sur le cluster. Il supporte :
ˆ Les jointures INNER JOIN, LEFT JOIN entre tables.
ˆ Les sous-requêtes imbriquées.
ˆ Les fenêtres (WINDOW) analytiques.
ˆ Les CTE (WITH ... AS).

17.3 Activer le Multi-Stage Engine


1 SET useMultistageEngine = true ;
2
3 SELECT o . country , p . category , SUM ( o. amount )
4 FROM orders_olap o
5 JOIN products_dim p ON p . product_id = o . product_id
6 GROUP BY o . country , p . category
7 ORDER BY SUM ( o . amount ) DESC ;

Listing 17.1  Activation via option

17.4 Flux d'exécution multi-stage

Stage 1 : Stage 2 : Stage 3 : Stage 4 :


Scan orders_olap Scan products_dim Join + GroupBy Sort + Limit

Figure 17.1  Pipeline d'exécution du Multi-Stage Engine

43
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY
Astuce pratique
Le Multi-Stage Engine ouvre la porte à un vrai usage de Pinot comme Data Warehouse
interactif, proche d'un Snowake. Les jointures distribuées restent toutefois plus coûteuses
que le scan d'une table dénormalisée.

17.5 Cas d'usage du Multi-Stage


ˆ Data Warehouse fédéré : dimensions externes mises à jour fréquemment.
ˆ Self-service analytics : laisser l'analyste faire ses propres joins.
ˆ Audit trail : joindre logs et dimension utilisateurs.

Cours OLAP temps réel 44


Chapitre 18

Patterns d'architecture avec Pinot

18.1 Pattern 1 : Lambda Architecture

Batch Layer
(S3/HDFS)

Pinot
Sources Dashboard
HYBRID

Speed Layer
(Kafka)

Figure 18.1  Lambda Architecture avec Pinot HYBRID

18.2 Pattern 2 : CQRS


Command Query Responsibility Segregation : séparer les écritures (OLTP Postgres) et
les lectures analytiques (OLAP Pinot). Spring Boot applique la commande sur Postgres, émet un
événement Kafka, et Pinot met à jour sa vue OLAP.

18.3 Pattern 3 : Event Sourcing


Chaque changement d'état est un événement immutable poussé dans Kafka. Pinot reconstruit
la vue matérialisée en continu. Idéal pour l'audit, le debugging historique et la conformité régle-
mentaire.

18.4 Pattern 4 : Funnel Analytics


Typique des produits web : on veut savoir combien d'utilisateurs passent de l'étape A à l'étape
B puis C. Pinot fournit la fonction FUNNEL_COUNT pour ces cas d'usage.
1 SELECT FUNNEL_COUNT (
2 STEPS ( event_name = ' view_product ' ,
3 event_name = ' add_to_cart ' ,
4 event_name = ' purchase ') ,
5 CORRELATE_BY ( user_id ) ,
6 SETTINGS ( ' window =86400000 ')
7 ) AS steps
8 FROM user_events
9 WHERE event_time > ago ( '1 d ') ;

45
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

Listing 18.1  Exemple de funnel

Cours OLAP temps réel 46


Chapitre 19

Conclusion

Synthèse
Ce cours a présenté Apache Pinot de bout en bout : de la théorie OLAP/OLTP à l'inté-
gration avec Spring Boot, en passant par le design ETL, la modélisation relationnelle 3NF,
la modélisation dimensionnelle en étoile et le déploiement via Docker Compose. Le projet
pratique fourni permet de tout expérimenter localement.

19.1 Pour aller plus loin


ˆ Documentation ocielle : [Link]
ˆ StarTree Cloud : ore managée.
ˆ Livre  The Data Warehouse Toolkit  de Ralph Kimball.
ˆ  Designing Data-Intensive Applications  de Martin Kleppmann.
ˆ Conférences : Apache Con, Current (Conuent), Data Council.

19.2 Remerciements

Dr. BADR EL KHALYLY


Merci pour votre attention

Année universitaire 20252026

47
Chapitre 20

Glossaire

ACID
Atomicity, Consistency, Isolation, Durability  propriétés transactionnelles des SGBDR clas-
siques.
BASE
Basically Available, Soft state, Eventual consistency  modèle des systèmes NoSQL distribués.
Broker
Composant Pinot recevant les requêtes SQL et les distribuant aux serveurs.
CTE
Common Table Expression  sous-requête nommée dans une clause WITH.
CQRS
Command Query Responsibility Segregation  séparation des modèles d'écriture et de lecture.
Dimension
Table décrivant le contexte d'un fait (client, produit, temps).
Data Warehouse
Entrepôt de données centralisé pour l'analyse.
ETL
Extract, Transform, Load  pipeline d'alimentation d'un DW.
ELT
Extract, Load, Transform  variante où la transformation a lieu après le chargement.
Fait Mesure quantitative centrale d'un schéma dimensionnel.
Granularité
Niveau de détail du grain d'une table de faits.
HDFS
Hadoop Distributed File System  stockage distribué utilisé comme stockage profond.
HYBRID
Table Pinot combinant OFFLINE et REALTIME.
JDBC
Java Database Connectivity  API standard d'accès aux bases.
Kafka
Bus de messages distribué, utilisé pour le streaming temps réel.
Multi-Stage Engine
Moteur Pinot v2+ supportant les jointures distribuées.
OLAP
Online Analytical Processing  traitement analytique en ligne.

48
Apache Pinot + Spring Boot Dr. BADR EL KHALYLY

OLTP
Online Transaction Processing  traitement transactionnel en ligne.
Segment
Unité immutable de stockage d'une table Pinot.
SCD
Slowly Changing Dimension  gestion de l'historique des dimensions.
Schéma en étoile
Modèle dimensionnel avec une table centrale de faits et des dimensions aplaties autour.
Schéma en ocon
Variante normalisée où les dimensions sont éclatées en sous-tables.
Star-Tree
Index de pré-agrégation multi-dimensionnelle propre à Pinot.
Tenant
Groupe logique de ressources Pinot permettant l'isolation.
Upsert
Opération combinant INSERT et UPDATE, supportée sur les tables REALTIME.
Zookeeper
Service de coordination distribuée, support métadonnées du cluster Pinot.

Cours OLAP temps réel 49


Chapitre 21

Bibliographie et ressources

21.1 Livres de référence


ˆ Ralph Kimball, The Data Warehouse Toolkit, 3e édition, Wiley, 2013.
ˆ W. H. Inmon, Building the Data Warehouse, 4e édition, Wiley, 2005.
ˆ Martin Kleppmann, Designing Data-Intensive Applications, O'Reilly, 2017.
ˆ Craig Walls, Spring in Action, 6e édition, Manning, 2022.

21.2 Documentation ocielle


ˆ Apache Pinot : [Link]
ˆ Apache Kafka : [Link]
ˆ Spring Boot : [Link]
ˆ Docker Compose : [Link]

21.3 Articles et conférences


ˆ LinkedIn Engineering Blog :  Introducing Pinot .
ˆ Uber Engineering :  Real-time Analytics at Uber .
ˆ StarTree Blog : [Link]

21.4 Communauté
ˆ Slack Apache Pinot : [Link].
ˆ GitHub : [Link]
ˆ Conférences : ApacheCon, Current, Data Council.

Ce document a été rédigé et mis en page avec LATEX par


Dr. BADR EL KHALYLY
Cours Apache Pinot + Spring Boot  2025/2026

50

Vous aimerez peut-être aussi