Les SGBD relationnels (SQL) atteignent leurs limites face aux besoins modernes :
| Probleme | Explication |
|---|---|
| Volume massif | Google, Facebook, Amazon gerent des petaoctets de donnees |
| Distribution | Donnees reparties sur des milliers de serveurs (data centers) |
| Objets complexes | Donnees heterogenes, imbriquees, pas toujours tabulaires |
| Scalabilite | Les jointures et ACID coutent cher en environnement distribue |
NoSQL = "Not Only SQL" (propose par Carl Strozzi). Ce n'est pas un remplacement du SQL, mais un complement pour les cas ou le relationnel est inadapte.
graph LR
subgraph Relationnel
A[CUSTOMER] -->|FK| B[ADDRESS]
A -->|FK| C[ORDER]
C -->|FK| D[ORDER_ITEM]
D -->|FK| E[PRODUCT]
end
subgraph Agregat NoSQL
F["{ id:1, name:'Guido',
billingAddress:{...},
orders:[{items:[...]}] }"]
end
| Relationnel | Agregat (NoSQL) | |
|---|---|---|
| Structure | Tables, lignes, colonnes predefinies | Objets imbriques, schema libre |
| Liens | Jointures entre tables | Donnees regroupees dans un document |
| Distribution | Difficile (donnees liees = meme noeud) | Facile (agregat = unite de distribution) |
Les SGBD relationnels respectent ACID :
- Atomicity : transaction tout-ou-rien
- Consistency : coherence et integrite maintenues
- Isolation : transactions independantes
- Durability : ecriture definitive et fiable
En distribue, maintenir ACID a un cout enorme en performance. Les BD NoSQL relachent ACID pour gagner en scalabilite.
graph TD
C["C - Consistance<br/>Tous les noeuds voient<br/>les memes donnees"]
A["A - Disponibilite<br/>(Availability)<br/>Le systeme repond<br/>meme si des noeuds tombent"]
P["P - Tolerance au<br/>partitionnement<br/>Fonctionne malgre<br/>des coupures reseau"]
C --- CA["CA : SGBDR classiques<br/>(MySQL, PostgreSQL, Oracle)"]
C --- CP["CP : MongoDB, HBase,<br/>Redis"]
A --- CA
A --- AP["AP : Cassandra,<br/>CouchDB, DynamoDB"]
P --- CP
P --- AP
On ne peut garantir que 2 des 3 proprietes simultanement.
| Combinaison | Sacrifice | Exemples |
|---|---|---|
| CA | Pas de tolerance partition | SGBDR classiques |
| CP | Pas toujours disponible | MongoDB, HBase, Redis |
| AP | Pas toujours consistant | Cassandra, CouchDB, DynamoDB |
- 2 data centers, 2 repliques de la BD
- Coupure reseau entre les deux
- Choix CP : on gele les ecritures (perte de disponibilite) pour garder la coherence
- Choix AP : on continue a lire/ecrire (risque d'incoherence entre les 2 sites)
Partitionnement horizontal des donnees sur plusieurs serveurs.
partition = hash(objet) mod n (n = nb de serveurs)
- Les objets accedes ensemble resident sur le meme noeud
- La charge est repartie uniformement
- Les objets peuvent etre repliques
Sharding dynamique avec un anneau logique :
graph TD
subgraph "Anneau de hachage"
direction LR
A["Noeud A"]
B["Noeud B"]
C["Noeud C"]
end
O1["Objet 1"] -->|"hash -> sens horaire"| A
O2["Objet 2"] -->|"hash -> sens horaire"| B
O3["Objet 3"] -->|"hash -> sens horaire"| C
O4["Objet 4"] -->|"hash -> sens horaire"| A
Regles :
- Noeuds et objets sont haches avec la meme fonction
- Un objet est affecte au premier noeud dans le sens horaire
- Noeud quitte l'anneau : ses objets vont au noeud suivant
- Noeud rejoint l'anneau : il recupere les objets selon sa position
Utilise par Cassandra notamment.
Framework de calcul distribue parallele (cree par Google).
flowchart LR
Input["Donnees<br/>d'entree"] --> Split["Splitting<br/>(decoupage)"]
Split --> M1["Map 1"]
Split --> M2["Map 2"]
Split --> M3["Map 3"]
M1 --> Shuffle["Shuffle<br/>(regroupement<br/>+ tri)"]
M2 --> Shuffle
M3 --> Shuffle
Shuffle --> R1["Reduce 1"]
Shuffle --> R2["Reduce 2"]
R1 --> Result["Resultat<br/>final"]
R2 --> Result
Les 2 fonctions a implementer :
Map(key, value) -> list(key1, value1)
Reduce(key1, list(value1)) -> value2
Exemple : compter les mots
Fichier : "A A C | C B D | A C D"
Map: "A A C" -> [(A,1),(A,1),(C,1)]
"C B D" -> [(C,1),(B,1),(D,1)]
"A C D" -> [(A,1),(C,1),(D,1)]
Shuffle: A -> [1,1,1] B -> [1] C -> [1,1,1] D -> [1,1]
Reduce: A -> 3, B -> 1, C -> 3, D -> 2
Architecture Master/Worker :
- Le Master distribue les taches Map et Reduce aux Workers
- Worker : 3 etats =
idle,in-progress,completed - On pousse le programme vers les donnees (pas l'inverse)
- Les mises a jour ne suppriment pas l'ancien enregistrement
- Elles marquent l'ancienne version comme obsolete et ajoutent une nouvelle version
- Plusieurs versions coexistent, une seule est la plus recente
- Necessite un nettoyage periodique des versions obsoletes
- Chaque noeud maintient un vecteur d'horloge :
V[0], V[1], ..., V[n] - Chaque entree = horloge d'un noeud du systeme
- Permet de detecter les conflits lors de mises a jour concurrentes
- Valeurs d'horloge = timestamps, numeros de version, etc.
High Availability Distributed Object Oriented Platform
| Module | Role |
|---|---|
| HDFS | Systeme de fichiers distribue |
| Hadoop Common | Bibliotheques et utilitaires |
| YARN | Gestion des ressources du cluster |
| MapReduce | Implementation du modele MapReduce |
graph TD
NoSQL["BD NoSQL"]
KV["Cle-Valeur<br/>Redis, Riak, Voldemort"]
COL["Colonne<br/>Cassandra, HBase"]
DOC["Document<br/>MongoDB, CouchDB"]
GRA["Graphe<br/>Neo4j, OrientDB"]
NoSQL --> KV
NoSQL --> COL
NoSQL --> DOC
NoSQL --> GRA
| Cle-Valeur | Colonne | Document | Graphe | |
|---|---|---|---|---|
| Modele | Paires cle/valeur | Familles de colonnes | Documents JSON/XML | Noeuds + Relations |
| Scalabilite | +++ | +++ | ++ | ++ |
| Complexite | + | ++ | ++ | +++ |
| Oriente agregat | Oui | Oui | Oui | Non |
| Exemples | Redis, Riak | Cassandra, HBase | MongoDB, CouchDB | Neo4j, OrientDB |
Principe : hashmap distribuee geante. La valeur est opaque (la BD ne connait pas sa structure).
cle1 -> valeur (string, JSON, blob...)
cle2 -> valeur
cle3 -> valeur
Operations CRUD :
create(key, value)/read(key)/update(key, value)/delete(key)
Interface : HTTP REST
| Forces | Faiblesses |
|---|---|
| Simple, performant | Trop simple pour donnees complexes |
| Excellente scalabilite horizontale | Interrogation uniquement par cle |
| Haute disponibilite | Complexite reportee sur l'applicatif |
Cas d'usage : cache, sessions, preferences utilisateur, paniers d'achat, logs, capteurs.
Principe : stockage par colonnes (pas par lignes). Nombre de colonnes dynamique et variable par ligne.
Concepts cles :
- Colonne : couple cle/valeur
- Super-colonne : colonne contenant d'autres colonnes
- Famille de colonnes : regroupement de colonnes (~ table)
| Forces | Faiblesses |
|---|---|
| Donnees semi-structurees | Mauvais pour donnees interconnectees |
| Naturellement indexe | Requetes doivent etre pre-ecrites |
| Bonne scalabilite + MapReduce | Maintenance a l'ajout/suppression de colonnes |
| Temps reel | Pas de requetes ad-hoc |
Cas d'usage : logging (Netflix), optimisation de recherche (eBay), BI (Adobe), analyse temps reel, compteurs.
Principe : extension du cle-valeur ou la valeur est un document semi-structure (JSON, XML).
{
"id": 1,
"nom": "Dupond",
"adresses": [
{"ville": "Paris", "cp": "75001"}
],
"commandes": [...]
}- Schemaless : pas de schema prealable
- Documents heterogenes dans la meme collection
- Requetes possibles sur le contenu des documents
| Forces | Faiblesses |
|---|---|
| Simple mais puissant (structures imbriquees) | Inadapte aux donnees interconnectees |
| Pas de maintenance schema | Requetes limitees aux cles/index |
| Bonne expressivite de requetage | Lent sur grandes requetes (-> MapReduce) |
Cas d'usage : CMS, evenements/capteurs, analytics temps reel, catalogues produits, messagerie.
Principe : base sur la theorie des graphes. Noeuds + Relations + Proprietes.
graph LR
A["Personne<br/>nom: Alice"] -->|AMIE_DE| B["Personne<br/>nom: Bob"]
A -->|TRAVAILLE_A| C["Entreprise<br/>nom: ACME"]
B -->|TRAVAILLE_A| C
A -->|ACHETE| D["Produit<br/>nom: TV"]
- Relations orientees et avec proprietes
- Beaucoup plus rapide que les SGBDR pour les traversees de graphe
| Forces | Faiblesses |
|---|---|
| Puissant pour donnees liees | Sharding plus difficile |
| Tres rapide pour les parcours | |
| Langages etablis (Cypher, SPARQL) |
Cas d'usage : reseaux sociaux, recommandations, BI, geospatial, genealogie, detection de fraude, routage.
Triple Store RDF : structure sujet-predicat-objet, requete via SPARQL, fondation du Web Semantique.
- BD orientee graphe, ecrite en Java (GPLv3)
- Transactionnelle (respecte ACID - exception parmi les NoSQL !)
- Schemaless : pas de schema preetabli
- Supporte des milliards de noeuds et relations
- Langage de requete : Cypher
- Acces web :
http://localhost:7474
graph LR
subgraph "Noeud (Node)"
N1["Labels: Personne, Salarie<br/>Proprietes:<br/> nom: 'Dupond'<br/> prenom: 'Marcel'"]
end
subgraph "Noeud"
N2["Label: Produit<br/>Proprietes:<br/> nom: 'TV'<br/> taille: 50"]
end
N1 -->|"ACHAT<br/>date: 09/12/2018"| N2
| Element | Description |
|---|---|
| Propriete | Attribut cle/valeur sur un noeud ou une relation (types Java) |
| Noeud | Entite avec 0..n labels et 0..n proprietes |
| Relation | Lien oriente entre 2 noeuds, avec 1 type (obligatoire) et 0..n proprietes |
Noeuds :
() -- noeud anonyme
(n) -- noeud stocke dans variable n
(:Personne) -- noeud avec label Personne
(n:Personne) -- noeud Personne dans variable n
(n:Personne:Salarie) -- noeud avec 2 labels
Relations :
(a)--(b) -- relation non orientee
(a)-->(b) -- relation orientee a -> b
(a)-[:AMIE]->(b) -- relation de type AMIE
(a)-[r:AMIE|COLLEGUE]->(b) -- type AMIE ou COLLEGUE, stockee dans r
-- Noeud simple
CREATE (n:Personne {nom: 'Dupond', prenom: 'Marcel'})
-- Noeud + relation + noeud en une fois
CREATE (a:Personne {nom:'Alice'})-[:AMIE]->(b:Personne {nom:'Bob'})
-- Relation entre noeuds existants (dans le meme bloc)
CREATE (n1)-[:CONNAIT {depuis: 2020}]->(n2)
-- Relations chainees
CREATE (a)-[:AMIE]->(b)<-[:COLLEGUE]-(c)-- Tous les noeuds
MATCH (n) RETURN n
-- Par label
MATCH (n:Personne) RETURN n
-- Par propriete
MATCH (n:Personne {nom: 'Dupond'}) RETURN n
-- Par relation
MATCH (a {nom:'Alice'})-->(b) RETURN b
-- Par type de relation
MATCH (a)-[:AMIE]->(b) RETURN a, b
-- Relation a profondeur variable (2 a 5 sauts)
MATCH (a)-[*2..5]-(b) RETURN a, b
-- Plus court chemin
MATCH p = SHORTESTPATH((a)-[*1..10]-(b)) RETURN pMATCH (n:Personne)
WHERE n.age > 25 AND n.ville IN ['Paris', 'Nice']
RETURN n
-- Operateurs sur chaines
WHERE n.nom STARTS WITH 'Du'
WHERE n.nom ENDS WITH 'nd'
WHERE n.nom CONTAINS 'po'
WHERE n.nom =~ 'Mar.*' -- regex
-- Existence / Null
WHERE EXISTS(n.email)
WHERE n.email IS NULL-- Ajouter/modifier une propriete
MATCH (n {nom: 'Dupond'})
SET n.age = 42, n.ville = 'Paris'
-- Ajouter un label
MATCH (n {nom: 'Dupond'})
SET n:VIP
-- Remplacer TOUTES les proprietes (= ecrase)
MATCH (n {nom: 'Dupond'})
SET n = {nom: 'Dupond', age: 43}
-- Fusionner les proprietes (+= conserve les existantes)
MATCH (n {nom: 'Dupond'})
SET n += {age: 43, email: 'dupond@mail.com'}MATCH (n {nom: 'Dupond'})
REMOVE n.age -- supprime la propriete age
MATCH (n {nom: 'Dupond'})
REMOVE n:VIP -- supprime le label VIP-- Supprimer un noeud (SANS relations, sinon erreur)
MATCH (n {nom: 'Dupond'}) DELETE n
-- Supprimer les relations d'un noeud
MATCH (n {nom: 'Dupond'})-[r]->() DELETE r
-- Supprimer un noeud ET toutes ses relations
MATCH (n {nom: 'Dupond'}) DETACH DELETE n| Clause | Usage | Exemple |
|---|---|---|
RETURN |
Afficher les resultats | RETURN n.nom, n.age |
LIMIT |
Limiter le nb de resultats | RETURN n LIMIT 10 |
DISTINCT |
Eliminer les doublons | RETURN DISTINCT b |
ORDER BY |
Trier | ORDER BY n.nom DESC |
COUNT(*) |
Compter | RETURN COUNT(*) |
AVG / SUM / MIN / MAX |
Agregats | RETURN AVG(n.age) |
WITH |
Chainage de requetes | voir ci-dessous |
FOREACH |
Boucle de traitement | voir ci-dessous |
LABELS(n) |
Labels d'un noeud | RETURN LABELS(n) |
TYPE(r) |
Type d'une relation | RETURN TYPE(r) |
ID(n) |
Identifiant interne | RETURN ID(n) |
-- Departements avec plus d'1 noeud lie
MATCH (n {nom:'Val'})--(b)
WITH b.dept AS dept, COUNT(*) AS nb
WHERE nb > 1
RETURN dept, nb-- Creer des amis depuis une liste
MATCH (n {nom: 'Alice'})
FOREACH (name IN ['Bob', 'Charlie'] |
CREATE (n)-[:AMIE]->(:Personne {nom: name}))-- Creer un index
CREATE INDEX ON :Personne(nom)
-- Supprimer un index
DROP INDEX ON :Personne(nom)
-- Contrainte d'unicite
CREATE CONSTRAINT ON (p:Personne) ASSERT p.email IS UNIQUE
-- Supprimer une contrainte
DROP CONSTRAINT ON (p:Personne) ASSERT p.email IS UNIQUENoSQL = Not Only SQL (complement du SQL, pas remplacement)
CAP : on choisit 2 parmi {Consistance, Availabilite, Partition-tolerance}
- SGBDR = CA
- NoSQL = CP ou AP
4 modeles NoSQL :
Cle-Valeur -> Redis, Riak (cache, sessions)
Colonne -> Cassandra, HBase (analytics, logs)
Document -> MongoDB, CouchDB (CMS, catalogues)
Graphe -> Neo4j, OrientDB (reseaux sociaux, recommandation)
Fondements :
Sharding = repartition horizontale des donnees
Consistent Hash = anneau avec hash(noeud) et hash(objet)
MapReduce = Map(k,v)->[(k1,v1)] puis Reduce(k1,[v1])->v2
MVCC = multi-versioning au lieu de remplacement
Vector Clocks = vecteurs d'horloge pour gerer la concurrence
Cypher (Neo4j) :
CREATE (n:Label {prop: val}) -- creer
MATCH (n:Label) WHERE ... RETURN n -- chercher
SET n.prop = val -- modifier
REMOVE n.prop / n:Label -- supprimer prop/label
DELETE n / DETACH DELETE n -- supprimer noeud
Motifs : (a)-[:TYPE]->(b) / (a)-[*2..5]-(b)