Pratiquer le NoSQL grâce à la Coupe du Monde de football

Le Use Case : devenir sélectionneur d’un jour

En cette période de Coupe du Monde de football, il est de coutume de dire que la France a 60 millions de sélectionneurs. Pour vous mettre dans la peau d’un sélectionneur, la recette est simple : un peu de NoSQL, une pointe de Maven, une pincée de Cassandra et un soupçon de MongoDB suffisent.

Dans ce billet nous allons mettre en œuvre le back-office d’une application qui s’adresse donc potentiellement à 60 millions d’utilisateurs.

Cette application permettrait à chacun :

  • de choisir son dispositif tactique parmi une liste prédéfinie : 4-4-2, 4-3-3, 3-5-2…
    Pour les non-initiés, chaque chiffre désigne le nombre de joueurs par ligne. Par exemple : dans un 4-4-2, il y a 4 défenseurs, 4 milieux, et 2 attaquants.
  • de choisir ses joueurs pour chaque ligne, parmi une liste prédéfinie et en fonction du dispositif retenu : gardien, défenseurs, milieux, attaquants.

Au-delà de son côté très « au goût du jour », ce use case va nous confronter à des choix techniques concrets pour les solutions NoSQL.

Principalement nous allons devoir adresser les problématiques suivantes :

  • Problématique 1 : Comment exposer efficacement des listes prédéfinies et invariantes : dispositifs tactiques, joueurs par ligne ?
  • Problématique 2 : Comment permettre à chaque utilisateur de stocker son équipe, et de la retrouver (pour pouvoir la modifier) lors d’une connexion ultérieure ?
  • Problématique 3 : Comment déterminer à tout moment les joueurs les plus souvent retenus par les utilisateurs ?

Le choix fait pour cet article est de développer en Java, avec pour chaque base NoSQL un niveau d’abstraction au-dessus des drivers de base afin de conserver une modélisation objet de nos entités métier.

De plus nous avons fait le choix de l’outil Maven pour le build de notre projet.

L’ensemble des sources est accessible ici : https://github.com/rgirodon/nosqlbench

Problématique 1 : la gestion des caches

La problématique 1 revient à la gestion de caches dans une application.

Pour la traiter nous avons choisi de stocker ces données de référentiel (les formations, les joueurs par poste) dans Redis.

Redis est une base de données orientée clef-valeur, à très haute performances, car tout est stocké en mémoire.

Redis permet de stocker des types simples : String, Set, List, Map et OrderedSet. La manipulation des données se fait via un ensemble de commandes de base, rendues disponibles par un driver dans la plupart des langages.

Redis est distribué par Pivotal, et c’est donc sans surprise que le projet Spring-Data-Redis offre une excellente solution pour attaquer Redis.

Commençons par ajouter les dépendances Maven dans notre pom.xml :

NoSQL : dépendances Maven

Il nous faut ensuite configurer notre contexte spring :

Dans un 1er temps nous définissons simplement un propertyPlaceHolder nous permettant d’externaliser dans un fichier de properties le host et le port sur lequel tourne Redis.

Puis nous définissons une RedisConnectionFactory basée sur Jedis (connecteur plus bas niveau Java – Redis).

Nous poursuivons en définissant un StringRedisTemplate qui nous permettra de réaliser toutes nos opérations de persistance vers Redis, avec une gestion facilitée des String (encodage notamment). A noter que nous injectons notre RedisConnectionFactory dans ce template.

Enfin, nous activons le component scanning sur un sous-package de notre projet.

Nous allons ensuite développer notre entité métier Tactic, représentant un dispositif tactique donné :

NoSQL : développer l'entité métier

Il s’agit d’un POJO classique, nous lui ajouterons simplement quelques méthodes utilitaires pour son stockage dans Redis.

Dans Redis, chaque instance sera stockée sous la forme d’une Map, avec une Entry par attribut. Cette Map sera rangée sous une clé définie par son label :

‘tactic::442’ => {‘label’ : ‘4 4 2’, ‘nbGoalKeepers’ : ‘1’, ‘nbDefenders’ : ‘1’, ‘nbMidfields’ : ‘1’, ‘nbForwards’ : ‘1’}

Nous allons ensuite développer notre Dao, RedisDao, nous permettant de réaliser nos opérations de persistance.

Nous déclarons notre Dao comme un Repository classique.

Nous déclarons un attribut de type HashOperations, qui nous permettra de gérer des entrées de type Map<String, String> dans Redis stockées sous des clés de type String.

Nous injectons dans cet attribut notre StringRedisTemplate.

C’est aussi simple que cela, il n’y a plus qu’à implémenter les opérations de persistance.

L’ajout d’entrées :

La récupération d’entrées :

NoSQL : récupération d'entrées

A noter l’utilisation de la commande KEYS avec un pattern de clé à rechercher, et le fait que l’on passe par un format de conversion Entité métier <-> Map.

L’utilisation de KEYS peut prêter à polémique, car cette commande n’est pas très performante. Dans notre cas de figure ce n’est pas très grave car nous avons peu de données. Pour contourner cela, nous pourrions stocker toutes nos clés de Tactic dans un Set, puis rechercher uniquement ces clés là.

Et enfin la suppression d’entrées :

NoSQL : suppression d'entrées

Cela peut être testé via la classe de test suivante :

On commence par définir le Runner Spring comme environnement d’exécution pour ce JUnit TestCase.

On définit ensuite quel fichier de contexte Spring doit être monté.

On injecte la Dao à tester dans notre classe de test.

On assure via la méthode cleanAll un nettoyage de la base avant chaque méthode de test.

Enfin, on teste l’ajout et la recherche de tactiques dans notre dernière méthode.

La suite

Dans les prochains billets, nous verrons comment traiter les problématiques 2 et 3, avec MongoDB puis avec Cassandra.

 

Inscription newsletter

Ne manquez plus nos derniers articles !