Tech Talk : Cassandra Java Driver 3.0


Première partie : opérations de base

Bonjour chers NoSqliens et NoSqliennes ! Nous allons continuer notre série d’articles autour des bases NoSQL, avec cette fois la découverte du driver Java de la fameuse base Cassandra ( C* pour les intimes).

Le concept est simple : nous allons utiliser une application déjà existante et imaginer comment réécrire ses fonctionnalités en utilisant C* et son driver Java. L’application à réécrire n’est autre que SFEIR Map, dont nous avons déjà parlé.

Note : le driver Java C est en version bêta et donc encore sujet au changement !

 

Data Modeling

C* est une base de données non relationnelle, répartie et orientée colonnes, on y retrouve la notion de :

  • Keyspace
  • Table
  • Partition (colonne)

Pour la modélisation de données, on vas utiliser le CQL (Cassandra Query Language), un langage très proche du SQL, pour communiquer avec C*.

Pour notre modèle de données, nous allons avoir besoin d’un keyspace sfeirmap qui contient une table collaborateurs, une table adresses et une table clients.

CREATE TABLE adresses (id uuid PRIMARY KEY, voie text, code text, ville text, coordonnees map<text,float>);

Cassandra JDriver Picture 1

CREATE TABLE clients (id uuid PRIMARY KEY, nom text, adresse uuid);

CREATE TABLE collaborateurs (email text PRIMARY KEY, nom text, bibliographie text, role text, technos set<text>, teamleader text, adresse uuid, client uuid);

Cassandra JDriver Picture 3

  • Les champs déclarés PRIMARY KEY sont utilisés par C* pour la répartition des données entre les noeuds et leur présence est obligatoire pour toute requête lancée sur la table.
  • Il n’y a aucune relation entre les tables (C* ne sait pas et ne pourra pas savoir que le champ adresse de la table clients référence le champ id de la table adresses), il faut gérer les contraintes dans l’applicatif.

Une fois le modèle établi, on peut commencer à réécrire les requêtes avec le driver Java de C*.

Connexion

Pour commencer à lire et à écrire dans notre keyspace sfeirmap, il faut au préalable se connecter à notre cluster C*, la classe Cluster est justement là pour ça :

Cluster cluster = Cluster.builder().addContactPoint(<host>).build();

À partir de cet objet, on récupère une session sur notre keyspace :

Session session = cluster.connect("sfeirmap");

À ce niveau, on peut commencer à faire des opérations sur la table des collaborateurs, comme compter le nombre de collaborateurs en base :

Statement statement = QueryBuilder.select().countAll().from("sfeirmap", "collaborateurs");
Long count = session.execute(statement).one().getLong("count");

Il ne faut pas oublier de fermer la session et le cluster après utilisation :

session.close();
cluster.close();

CRUD

Insertion

Imaginons qu’on veuille ajouter une adresse dans la table adresses :

Map<String,Float> coordonnees = new HashMap<String,Float>();
coordonnees.put("latitude", 2.27255F);
coordonnees.put("longitude", 48.88052F);

statement = QueryBuilder.insertInto("sfeirmap", "adresse")
     .value("id", UUID.randomUUID())
     .value("code","92200")
     .value("ville","Neuilly-sur-Seine")
     .value("voie","46, Rue jacques Dulud")
     .value("coordonnees", coordonnees);
session.execute(statement);

Le principe est le même pour l’insertion dans les tables clients et collaborateurs.

Recherche

Au chargement de l’application SfeirMap, il faut charger l’ensemble des collaborateurs pour pouvoir afficher leurs localisations dans la Map, mais a ce niveau, on n’a pas besoin de toutes les informations concernant chaque collaborateur.

Pour chaque collaborateur, on veut juste récupérer son “email” et ses “coordonnées” c’est a dire les coordonnées du client où il travaille.
– “Oui, mais c’est simple ça, il suffit de faire une jointure entre les tables collaborateurs, clients et adresses et récupérer les champs qu’on veut :)”
– “Pas mal comme raisonnement, mais dans C* et le monde NoSQL en général il n’y a pas de notion de jointure ! Ce sont des bases réparties et c’est très compliqué de faire des jointures sur des données distribuées tout en gardant un niveau élevé de performances”
– “On fait comment alors ?”
– “Let’s do it the C* way !”

Avec C* on fait du Query Driven Design : en gros on crée nos tables pour qu’elles répondent a nos requêtes. Pour simplifier, une table par requête quitte a dédoubler la data pour cette requête.

CREATE TABLE collaborateurs_par_coordonees_clients (email text PRIMARY KEY, coordonnees map<text,float>) ;

Cassandra JDriver Picture 4
Ce qui nous permet de chercher nos collaborateurs et leurs coordonnées :

statement = QueryBuilder.select()
     .column("email")
     .column("coordonnees")
     .from("sfeirmap", "collaborateurs_par_coordonees_clients");
ResultSet results = session.execute(statement);

On peut maintenant afficher les petites icônes sur la Map en utilisant les coordonnées.
Cassandra JDriver Dev1

Imaginons maintenant qu’on veuille gérer l’affichage des informations d’un collaborateur avec un clic sur son icône.

Sachant qu’on a le mail du collaborateur, au moment du clic, il faut lancer une requête de recherche dans C* pour récupérer toutes les informations le concernant. Cette fois, ces infos sont dans la table collaborateurs :

statement = QueryBuilder
     .select()
     .all()
     .from("sfeirmap", "collaborateurs")
     .where(eq("email", "monmail@sfeir.com"));
results = session.execute(statement);

Ce qui se traduit par : je veux chercher le collaborateur qui a le champ email égal à “monmail@sfeir.com”.

Une fois la requête lancée, on peut afficher les informations du collaborateur :

Mise à jour

Supposons maintenant que je viens de finir une super formation Agile et que je veuille la rajouter à la liste de mes technos. Je vais donc chercher ma petite icône sur la map, je clique dessus et je fais ma mise à jour :

Au clic sur le bouton enregistrer, il faut lancer une update sur C* pour mettre à jour les technos du collaborateur :

 

statement = QueryBuilder.update("sfeirmap", "collaborateurs")
     .with(add("technos", "Agile"))
     .where(eq("email", "mahjoub.o@sfeir.com"));
session.execute(statement);

Voilà ! Nice and Fast !

Suppression

Pour supprimer un collaborateur de la liste, rien de plus simple :

statement = QueryBuilder.delete()
     .from("sfeirmap", "collaborateurs")
     .where(eq("email", "zoghlami.o@sfeir.com"));
session.execute(statement);

Conclusion

Nous avons vu dans cette première partie, à travers l’application SfeirMap, les opérations de base réalisables avec le C* Java Driver. Dans la seconde partie, nous verrons comment faire des opérations un peu plus complexes sur les données C*, en intégrant Spark qui est un framework pour la manipulation des données !

Vous aimerez aussi...