[MUSIQUE] [MUSIQUE] [MUSIQUE] Cette leçon va donc porter sur les bases de données NoSQL qui sont une vaste famille regroupant un grand nombre de types de bases de données différentes, et qui se distinguent en fait des bases de données relationnelles classiques que nous avons vu jusqu'à présent par le fait qu'à l'origine elles n'implémentaient pas le langage SQL. Donc la logique de stockage de l'information est un peu différente, et les règles d'utilisation également. Nous aborderons toutes ces questions au cours de la leçon. L'objectif de cette leçon est donc de compléter un petit peu ce que nous avons appris des bases de données relationnelles en ouvrant le champ à l'exploration des bases de données NoSQL, et peut-être plus particulièrement à l'une d'entre-elles qui est la base de données Mongo. Au terme de cette leçon vous devriez être en mesure d'expliquer en quoi le monde NoSQL se différencie du monde des bases de données relationnelles, et vous devriez être capables d'utiliser un petit peu l'une de ces bases de données. Dans cette leçon nous parlerons tout d'abord des origines du NoSQL, puis nous passerons en revue les différents types de bases de données NoSQL et les systèmes de gestion de bases de données qui leurs sont associés, avant de concentrer notre attention plus particulièrement sur MongoDB qui est un type de base de données NoSQL, et pour terminer nous verrons comment les fonctions CRUD, donc Create, Read, Update, Delete, sont implémentées dans un système comme MongoDB. [MUSIQUE] Nous avons vu dans le leçon portant sur les bases de données relationnelles que ce type de base de données stocke les données dans des tables dont les colonnes ont des types bien définis, que ces tables peuvent être liées entre elles par des relations, que l'interrogation des données repose sur un langage standardisé, le SQL, et finalement que les transactions effectuées dans ces tables répondent en général au principe ACID, à savoir atomicité, cohérence, isolation et durabilité. Atomicité signifiant que toutes les modifications d'une transaction doivent être effectuées avec succès, faute de quoi l'ensemble de ces modifications doit être invalidé. Cohérence qu'une transaction n'est validée que si toutes les règles en vigueur sont respectées, sur le type de données, les contraintes, les primaires, valeurs nulles possibles ou pas, etc. Isolation signifie que l'exécution simultanée de deux transactions est équivalente à leur exécution séquentielle, donc une transaction n'affecte pas d'autres transactions. Et la durabilité signifie qu'après validation les données sont enregistrées de manière durable, indépendamment d'erreurs, de crashs ou d'autres dysfonctionnements qui peuvent survenir. La seconde génération Web a vu apparaître des services qui gèrent des très gros volumes de données comme Google, Amazon, Facebook, LinkedIn, etc. Et qui doivent faire face à de brusques afflux de trafic ponctuels. Afflux de trafic signifie généralement diminution du temps de réponse, diminution de l'enthousiasme des utilisateurs et perte de rentabilité, d'où la nécessité de maintenir les fonctionnalités et les performances en cas de forte demande, caractéristique que l'on appelle la scalabilité ou l'évolutivité. Ce maintien des fonctionnalités et des performances peut être obtenu par accroissement de puissance, et l'on parle alors de scalabilité verticale, ou par démultiplication des noeuds et distribution des services sur les noeuds du réseau, et l'on parle alors de scalabilité horizontale. Un meilleur ajustement des logiciels aux types de données gérées permet également d'accélérer le traitement des données et de maintenir la performance. On voit donc que les bases de données NoSQL regroupe un ensemble d'alternatives aux bases de données relationnelles, qui ont été développées dès la fin des années 90 pour répondre au besoin de maintien des performances de certains gros acteurs du Web qui gèrent de très grosses bases de données, de complexité faible à modéré. Les principales différences, caractéristiques des bases de données NoSQL se trouvent tout d'abord dans la forme de stockage des données, qui diffère pas mal de ce à quoi l'on est habitué dans le monde des bases de données relationnelles. Dans le fait de ne pas fournir, en tout cas à l'origine, d'implémentation du langage SQL. Dans le fait de ne pas apporter de support aux jointures, donc on ne peut pas faire de jointures dans les bases de données NoSQL. De fonctionner en système distribué, c'est-à-dire de distribuer les données sur plusieurs serveurs, et finalement une tendance à ne pas implémenter les règles, les principes ACID. Le principe de la scalabilité horizontale est donc de vouloir distribuer le service ou les données sur les nombreuses machines constituant un réseau, donc sur un ensemble de noeuds, conduit tout droit à ce théorème dit théorème CAP, qui stipule que seuls deux des trois critères de cohérence, de disponibilité, et de tolérance au partitionnement peuvent être satisfaits simultanément. Cohérence signifiant que tous les noeuds d'un système voient exactement les mêmes données au même moment. Disponibilité que chaque fois que l'on envoie une requête vers l'un des noeuds du système on est certain de recevoir une réponse. Soit en terme de succès ou d'échec de la requête, mais on reçoit une réponse. Et la notion de tolérance au partitionnement qui exprime l'idée en fait que dans un système distribué il arrive fréquemment que les différents nœuds puissent être isolés les uns des autres, soit parce qu'un nœud ne fonctionne plus, il a été victime d'un crash, une coupure de courant, des ruptures de communication, la communication en passe plus, etc. Dans le cas des systèmes NoSQL où on essaye de répartir la charge et l'information sur les nombreux nœuds d'un réseau, le partitionnement est une réalité, si bien que en fait il faut choisir de privilégier la cohérence ou la disponibilité. Dans le premier cas les systèmes que l'on appelle CP, donc plutôt cohérence et partitionnement, cela signifie que l'on attend une synchronisation des nœuds, avant d'assurer la réponse avec le risque d'avoir de temps en temps des timeout ou des messages d'erreur, et donc le critère de disponibilité n'est pas respecté, ou alors on va vers des solutions AP, donc où l'on privilégie la disponibilité. Dans ce cas-là le noeud que l'on interroge va renvoyer la dernière version disponible d'une donnée au niveau d'un nœud, ce qui veut dire qu'on accepte que tous les nœuds puissent ne pas être toujours à jour et des fois renvoyer des valeurs différentes. Après toute la question est de savoir quelle est la durée de mise à jour tolérable. On voit que les bases de données relationnelles, qui de par leur nature même, de par l'existence de relations entre les tables, se prêtent mal en fait à une distribution des données sur plusieurs machines différentes, se trouvent en général dans le registre CA, donc cohérence et disponibilité, mais ne se prêtent pas du tout à une scalabilité horizontale par répartition sur un réseau. [MUSIQUE] [MUSIQUE] Si l'on regarde d'un peu plus près le monde des bases de données NoSQL, on s'aperçoit qu'on peut distinguer quatre grandes familles de bases de données NoSQL, qui se distinguent par la manière dont elles stockent l'information. La première de ces familles est constituée par les bases de données de type clé-valeur, qui sont donc basées sur des dictionnaires, permettant d'accéder à la valeur d'un objet par l'intermédiaire d'une clé qui doit être unique. Comme exemple on peut voir ici que la clé peut être représentée par un prénom, Pierre ou Henri, qui donne accès à une série de valeurs, le type d'activité, l'âge, le type d'activité sportive, etc. Les principaux systèmes de gestion de bases de données qui implémentent ce type clé-valeur sont Redis et Voldemort, qui a donc été développé par LinkedIn pour gérer ses bases de données. Le second type de bases de données NoSQL est le type orienté colonne, qui s'apparente un petit peu au modèle relationnel, puisque les données en fait peuvent être représentées par des tables. Simplement le stockage est organisé par colonne, sur une base clé-valeur où on associe pour chaque colonne la clé avec la valeur de cette clé dans cette colonne. L'avantage de ce système est de permettre une gestion très dynamique d'un nombre très élevé de colonnes. Les principaux systèmes de gestion de bases de données qui implémentent ce modèle sont Cassandra, Hbase, BigTable et Vertica. Le troisème type de base de données NoSQL que l'on appelle orientée document propose également sur un paradigme clé-valeur en associant à la clé des documents qui sont de type JSON ou XML. Donc on a ici toujours le même exemple de Pierre et de Henri, avec Etudiant1 et Etudiant2 qui sont les clés, et derrière une syntaxe JSON qui donne les attributs de l'objet. Les systèmes de gestion de bases de données qui implémentent ce modèle sont principalement CouchDB, SimpleDB et MongoDB. Et finalement les bases de données NoSQL de type orienté graphe, qui se basent sur la théorie des graphes, sur les notions de noeuds, de relations et de propriétés pour stocker l'information ici relative aux étudiants Pierre et Henri. Le principal et seul, quasiment, système de gestion de bases de données, seul système un peu abouti, est Neo4J. Dans cette figure qui reprend les idées du théorème CAP, on a représenté en fait les différents types de systèmes de gestion de bases de données en fonction de leurs caractéristiques, de leur positionnement dans ce diagramme, en représentant en rouge orangé les systèmes gestion de bases de données relationnelles, notamment Postgres, MySQL etc. Les systèmes en vert de type clé-valeur, comme Voldemort et Redis, les systèmes orientés colonne en jaune, avec Cassandra du côté CP, Hbase et BigTable du côté AP, et finalement en bleu les systèmes SGBD orientés document, où l'on voit que MongoDB est un système qui est du côté de la disponibilité, alors que ses alter egos SimpleDB et CouchDB sont plutôt du côté de la cohérence. [MUSIQUE] [MUSIQUE] MongoDB est donc une base de données NoSQL libre de type orienté document. Dans cette base de données la notion de table qu'on avait dans les bases de données relationnelles est remplacée par la notion de collections. On a donc ici l'exemple de la table 'iii' des hôtels des Seychelles, et si l'on regarde comment ces données sont gérées dans Mongo on a ici un interface-utilisateur qui permet de voir cette collection d'objets, donc les hôtels, 124 objets dans la collection, et puis pour chaque objet une structure arborescente, l'identifiant et le type d'objet, la collection de ses propriétés, la géométrie et dans la géométrie les coordonnées. Cette représentation arborescente peut être transformée en représentation au format JSON, où on retrouve cette idée de collection dans la syntaxe propre au format JSON. Elle peut également être représentée dans une vue tabulaire, simplement avec des étages successifs que l'on peut parcourir pour accéder aux coordonnées ou aux propriétés des objets. Second élément important la notion de schéma de données, qui dans une base de données relationnelles est très importante, incontournable. Dans un système comme Mongo on est libre de stocker les données absoluement comme on veut, de mettre tout ce qu'on veut dans une collection. Par contre si l'on veut pouvoir utiliser les données stockées dans une base de données Mongo pour représenter des objets dans une carte, on a intérêt à ce que ces objets suivent une certaine structure pour retrouver en fait les coordonnées du point et les propriétés de l'objet. La meilleure manière de retrouver cette structure c'est de stocker au départ des objets qui ont cette structure. En d'autres termes la base de données Mongo n'est pas contraignante du point de vue schématisation des données, par contre de négliger la schématisation rend la vie beaucoup plus compliquée. Dénormalisation et jointure, dans un système de base de données relationnelles lorsque l'on veut ajouter un élément d'information, comme dans le cadre des hôtels des Seychelles si on souhaite ajouter l'information relative au propriétaire de ces hôtels. Comme plusieurs hôtels peuvent avoir le même propriétaire, pour éviter la redondance de données on créerait une table séparée, indirecte, qui recense les propriétaires, et on ajouterait dans la table d'origine une colonne avec l'identifiant des propriétaires, et l'on établirait ainsi une jointure entre ces deux tables. Ce processus de séparation de données c'est ce qu'on appelle, dans le monde base de données relationnelles, la normalisation. Notons au passage que l'une des faiblesses du monde relationnel, qui a déjà été évoquée lorsqu'on a présenté ce domaine, la difficulté qu'il y aurait ici à stocker l'information dans le cas où un hôtel aurait plusieurs propriétaires. Dans le cas de Mongo on pourrait bien entendu procéder d'une manière analogue en ajoutant dans le document JSON un champ ID du propriétaire, et puis en ayant une liste toujours au format JSON de propriétaires avec leur adresse. Notons au passage que la syntaxe JSON permet facilement de représenter le cas de plusieurs propriétaires. En réalité dans le monde NoSQL, comme on n'implémente pas les jointures, on préfère lister explicitement les éléments d'informations liés aux propriétaires, quite à vivre avec une certaine redondance. C'est pour cette raison que les systèmes NoSQL se prêtent particulièrement bien à gérer des grands volumes de données, mais des données qui ont une faible complexité avec peu de relations tabulaires. Dans le cas où on a des systèmes de données complexes, avec des tables qui sont liées les unes aux autres, le système base de données relationnelles reste plus intéressant en général. [MUSIQUE] Pour terminer nous allons voir quelques exemples d'implémentation des fonctions de base des bases de données, donc les fonctions de création, de lecture, de mise à jour et de suppression de données que l'on regroupe sous l'acronyme CRUD. On commence avec l'insertion de données. On va systématiquement comparer la syntaxe SQL avec la syntaxe que l'on retrouve dans Mongo. Donc dans le SQL, l'introduction d'un nouveau jeu de données dans la table des hôtels implique les mots clés INSERT INTO, la liste des colonnes et puis la liste des valeurs correspondant à ces colonnes. Dans le cas de Mongo on a quelque chose un peu d'équivalent avec simplement les mots-clés db qui réfèrent à la base de données en cours, hôtels c'est la collection visée, puis on insère dans cette collection un nouvel objet qui a quatre attributs, le nom, le nombre de chambres, le nombre de lits et le statut avec les valeurs de ces quatre attributs. Mise à jour de données, dans le cas SQL le mot-clé UPDATE, la table hôtels et puis le mot-clé SET, la variable que l'on souhaite changer, donc la variable chambres qui passe à 6, et puis la clause conditionnelle pour identifier l'hôtel sur lequel le nombre de chambres a augmenté à six. L'équivalent du côté Mongo avec le mot clé update également qui s'applique sur la collection hôtels, et puis simplement la référence à l'objet qui va changer, donc les objets dont le nom correspond à Beach Bungalows, et on va appliquer un set sur la variable chambre qui prend la valeur 6. Donc dans l'esprit quelque chose assez similaire au langage SQL. Pour la suppression de données, le DELETE FROM du langage SQL suivi du nom de la table, et puis de la clause conditionnelle que l'on retrouve à peu près à l'identique dans Mongo avec la fonction remove appliquée à la collection hôtels et puis on supprime le document qui a pour attribut nom Beach Bungalows. Enfin quelques exemples de requêtes plus générales, à commencer par la requête de sélection des hôtels dont le nombre de chambres est supérieur à 10, donc dans le SQL SELECT FROM classique avec une clause conditionnelle. Dans Mongo on retrouve le mot-clé find qui permet de rechercher des objets, le critère de recherche dans la première ligne, donc le champ chambres, et puis l'opérateur plus grand que caractérisé par l'esperluète qui précède le mot-clé gt, puis le critère 10, et dans la deuxième ligne les choses que l'on souhaite renvoyer. Comme l'identifiant de l'objet est renvoyé par défaut, on doit mettre un 0 si on peut pas avoir l'identifiant, et puis un 1 pour renvoyer le nom, donc c'est 0, 1, true, false. Un second exemple de requête basique similaire, donc compter le nombre d'objets renvoyés par la requête de sélection des hôtels dont le nombre de chambres est supérieur à 10, avec quelque chose d'assez équivalent dans Mongo, une fonction count, appliqué à la collection des hôtels, et portant sur le fait que le nombre des chambres est égal à dix. Dernier exemple de requête un peu plus élaborée où l'on cherche à lister le nombre d'hôtels qu'il y a dans chaque statut, pour chaque statut. Donc dans le SQL une requête classique avec un groupement par statut, et on compte dans chaque statut le nombre de candidats. Dans le cas de MongoBD on utilise le mot clé de la fonction d'agrégation portant sur la collection des hôtels avec comme règle de groupement le statut, et comme règle de calcul la somme. Ces quelques exemples montrent donc que dans un logiciel non SQL comme Mongo qui n'implémente pas le langage SQL, on dispose quand-même d'un langage de requête qui permet d'interroger les données de manière efficace, langage qui est d'ailleurs implémenté dans l'interface graphique. Mais avant de passer à l'interface graphique, regardons déjà comment se présentent les choses en ligne de commande qui est quand-même le mode d'utilisation initial et principal de Mongo, donc avec Mongo, la commande Mongo, on accède aux iii de Mongo, use Seychelles pour dire qu'on veut utiliser la base de données Seychelles, qui va s'appeler maintenant DB, et DB hotels, donc en référence la collection des hôtels et on cherche le premier objet de la collection qui est l'hôtel Beach Bungalow donc affiché en format JSON. Dans le cas d'un interface utilisateur graphique un peu plus élaboré, on a un petit outil de création de requêtes. On peut par exemple glisser le champ nom, et rechercher tous les hôtels dont le nom commence par b. Et on en trouve eh bien toute une série, série habituelle. Voilà. [MUSIQUE] [MUSIQUE] [MUSIQUE] Dans cette leçon nous avons donc exploré un petit peu le monde des bases données non SQL, nous avons notamment vu un petit peu pour quelles raisons ces bases de données avaient été développées comme alternatives aux modèles relationnels. Nous avons vu qu'il existait quatre types principaux de bases de données non SQL, caractérisées par la manière dont elles gèrent le stockage de l'information, nous avons ensuite approfondi un petit peu les caractéristiques de MongoBD, qui est donc une base de données de type orienté document. et nous avons vu comment la donnée était gérée, comment on gère la schématisation, la structuration de l'information, nous avons vu comment on gère les jointures et ce genre de choses. Et pour conclure, nous avons pris quelques exemples de l'implémentation des fonctionnalités principales d'interrogation de données, d'insertion de données, de mises à jour, de requêtes, en comparant la syntaxe du monde SQL avec la syntaxe utilisée dans un logiciel comme Mongo, pour arriver à la conclusion que, même si dans la forme les choses sont assez différentes, dans l'esprit, on fait assez facilement le passage de l'un à l'autre. Voilà c'était donc la dernière leçon de cette première partie du cours, alors j'en profite pour féliciter à l'avance tous ceux d'entre vous qui m'auront suivi jusque là [APPLAUDISSEMENT] bravo! [MUSIQUE] [MUSIQUE]