La première application consiste à réaliser un aperçu de cartographie rapide en se basant sur les 500 sites disponibles dans la partie “top sites” de l’interface web. En revanche, les données capitalisées sont disponibles uniquement sur la base d’un fichier CSV, qui est peu pratique à utiliser. De plus, mis à part la problématique du fichier, on a également pu remarquer précédemment que les données sont brutes et nécessitent un filtrage pour être pleinement exploitables. L’utilisation d’une base de données à ce stade de l’étude devenait donc nécessaire afin d’organiser les données récupérées de façon plus efficace.
Pour capitaliser les données du CSV de manière plus efficace, le choix s’est porté sur MongoDB. Ce système de gestion de base de données orientée documents est très pratique pour la sauvegarde et le traitement de données hétérogènes ou non-encore hiérarchisées. De plus, son fonctionnement sur la base d’objets JSON permet de pouvoir exploiter la base de données très facilement depuis du code JavaScript.
Toutes les données sont sauvegardées dans une unique collection afin de faciliter le traitement.
Gestion BDD (MongoDB) > BDD (webmap) > Collection (websites)
En effet, il n’était pas nécessaire d’utiliser un modèle relationnel vu la simplicité des données à sauvegarder : j’ai alors choisi d’ajouter un tableau d’objets imbriqués dans le schéma de stockage, afin de stocker les upstreams et downstreams pour un site donné. Les objets de ces tableaux référencent d’autres objets de la collection “websites”. Le schéma de stockage est décrit dans le code JavaScript ci-dessous.
const mongoose = require('mongoose'); require('mongoose-double')(mongoose); let websiteSchema = new mongoose.Schema({ url: String, globalRank: Number, country: String, countryRank: Number, bounceRate: mongoose.Schema.Types.Double, dailyPageviewsPerVisitor: mongoose.Schema.Types.Double, trafficFromSearchEngines: mongoose.Schema.Types.Double, totalSitesLinkingIn: Number, upstreams: [{ url: String, percentOfUniqueVisits: mongoose.Schema.Types.Double }], downstreams: [{ url: String, percentOfUniqueVisits: mongoose.Schema.Types.Double }] }); let Website = mongoose.model('Website', websiteSchema); module.exports = Website;
Le morceau de programme qui s’occupe de réaliser le transfert de données vers MongoDB fonctionne sur la même base que celui utilisé pour streamer le CSV vers Gephi. L’algorithme se déroule selon les étapes suivantes :
A la fin, la collection possède un document par site internet (qu’il fasse parti du top 500 ou qu’il soit un upstream ou dowstream). Chaque document possède (ou non) des données additionnelles décrites précédemment que l’on retrouve par exemple sur le document associé au site “bloomberg.com” présenté ci-dessous (les tableaux upstreams et downstreams ont été volontairement réduits à deux entrées).
{ "_id": "5a9d34e788263f6974f2e2ea", "url": "bloomberg.com", "__v": 20, "bounceRate": 0.656, "country": "united states", "countryRank": 155, "dailyPageviewsPerVisitor": 1.68, "downstreams": [{ "url": "drudgereport.com", "percentOfUniqueVisits": 0.014, "_id": "5a9d34f188263f6974f33257" }, { "url": "google.co.in", "percentOfUniqueVisits": 0.019, "_id": "5a9d34fa88263f6974f3783f" }, {...}], "globalRank": 434, "totalSitesLinkingIn": 97935, "trafficFromSearchEngines": 0.28, "upstreams": [{ "url": "google.co.in", "percentOfUniqueVisits": 0.021, "_id": "5a9d34f188263f6974f33261" }, { "url": "yahoo.com", "percentOfUniqueVisits": 0.02, "_id": "5a9d350188263f6974f39087" }, {...}] }
Pour réaliser la cartographie avec le logiciel Gephi des données disponibles dans la base MongoDB, j’ai à nouveau utilisé le plugin Streaming API afin de garder mes fonctions helpers écrites pour le premier concept d’application de stream depuis le CSV.
L’algorithme mis en place ici est bien plus simple que précédemment car les données sont déjà en place, filtrées et correctement formatées dans la collection MongoDB. Ainsi, le stream vers Gephi se déroule de la manière suivante à travers une fonction asynchrone :
Attention toutefois, Gephi utilise un type strict pour la déclaration des données dans ses colonnes et cela impose une limitation importante, qui est non contournable avec le JavaScript ! En effet, en JavaScript les nombres de type Float ou Int sont tous de type Number et un nombre comme “3.00” sera toujours ramené à “3”. Or cette simplification du fonctionnement du langage est problématique pour la colonne dailyPageViewsPerVisitors : la plupart des données sont des float, mais la valeur est entière sur quelques entrées, qui au final seront ignorées lors du stream… Pour contourner cette limitation, cette colonne est castée sous forme de String avant d’être streamée vers Gephi.
Après le stream, on se retrouve avec un graphe basique noir et blanc, spatialisé de manière aléatoire, comprenant (pour un scrap le 20/02/2018) un ensemble de 1290 nœuds et 9463 liens. Ce graphe est identique qu’à celui réalisé à partir du CSV en apparence, mais possède l’avantage d’avoir des données de meilleure qualité et est plus facilement exploitable dans Gephi : les colonnes sont pour les plupart de type “nombres” et sont utilisables à travers les filtres (sauf pour la colonne dailyPageViewsPerVisitors à cause de la limitation expliquée précédemment). Une possible solution serait de réécrire le programme avec un langage tel que le C++ qui possède un typage plus strict.