JavaScript &

les graph databases

Jean-Baptiste Musso

  • GitHub : @gulthor
  • Twitter : @jbmusso

ParisJS, 24 septembre 2014

Introduction

Objectif de la présentation :

  • comprendre ce qu'est une graph database
  • comprendre comment interagir avec une graph database depuis un environnement JavaScript (Node.js/Browser)
  • Un graphe est un ensemble de noeuds (vertex/vertices) connectés entre eux par des liens (edge/edges)
  • Chaque lien a une direction et un label
  • Les noeuds et les liens (éléments du graphe) peuvent avoir des propriétés qui les décrivent

likes

name: "jbmusso"

age: 29

type: "person"

since: 2012

name: "JavaScript"

type: "language"

Un graphe

Intérêt : permet de développer son application sans (trop) se soucier de la base graphe utilisée.

Framework Open Source

  1. Une API qui définit un graphe : Blueprints
  2. Un serveur : Gremlin Server, interface entre la database et l'application
  3. Un langage de requête : Gremlin

Tinkerpop

I. Modélisation

Example : Twitter

II. Requêtes

Gremlin

  • Objectif : un langage unique pour interagir avec un graph (= sorte de SQL des bases graph).
  • Pas un langage en soi : un DSL avec une implémentation de référence en Groovy (qui expose donc toute l'API Java).
  • Existe une variante expérimentale JavaScript.

Gremlin CRUD

// Ajouter Seb et Marie dans le graph
seb = g.addVertex(['type': 'user', 'name': 'Seb'])
marie = g.addVertex(['type': 'user', 'name': 'Marie'])

// Ajouter une relation de type follow de Seb vers Marie
g.addEdge(seb, marie, 'follows', ['since': 20140924])

// Delete
g.V('type', 'person').delete()
// Update
g.V('type', 'user').sideEffect({
  it.setProperty('type') = 'person'
})
// Récupérer tous les utilisateurs
g.V('type', 'user');

// Récupérer tous les utilisateurs qui s'appellent Bob
g.V('type', 'user').has('name', 'Marie');

Gremlin traversals

g.v(1).as('myself')  // Point de départ
  .out('follow')     // Trouver les utilisateurs que je follow
  .out('follow')     // Pour chacun, trouver ceux qu\'ils suivent
  .dedup()           // Filtrer les doublons éventuels
  .except('myself')  // Filtrer le point de départ

Principe général :

  • définir un point de départ (un ou n vertex)
  • naviguer vers d'autres vertex adjacents par l'intermédiaire d'éventuels edges

Exemple : trouver tous les utilisateurs suivis (followed) par les utilisateurs que je suis (follow) moi-même.

Requêtes types

  • Recommendation :
    • les clients qui ont acheté cet objet ont aussi acheté... (ex: Amazon)
    • vous pourriez devenir ami avec... (ex: Facebook).
  • Recherche de chemin :
    • X est connecté à Y par l'intermédiaire de... (ex: LinkedIn)
    • le chemin "le plus court" / "rapide" ou "le moins cher" entre mon entrepôt et mon client est...
    • détection de fraudes
  • Classement : algorithme PageRank (ex: Google).
  • Etc.

III. Gremlin JavaScript

gremlin-js

Client JavaScript bas niveau pour Gremlin Server (ex Rexster)

  • Etablit une connexion permanente à Gremlin Server (WebSocket)
  • Envoie des strings de Gremlin plus ou moins grandes, avec éventuellement des paramètres (bindings)
  • Exécute l'intégralité du script et renvoie un flux de résultats

https://github.com/gulthor/gremlin-client

API

client.execute(script, params, function(err, results) {
    if (!err) {
        console.log(results); // Array
    }
});

Mode callback

Mode stream

var gremlin = require('gremlin-client');
var client = gremlin.createClient(8182, 'localhost');

var script = 'g.V("name", userName)';
var params = { userName: 'Bob' };
var vertexStream = client.stream(script, params);

vertexStream.on('data', function(vertex) {
    console.log(vertex)
});

Streams

  • client.stream() renvoie un stream d'objets qui émet les résultats 1 par 1 à mesure que Gremlin Server les renvoie
  • chaque stream peut ensuite être .pipe() dans un autre stream Node.js (transform/write) : utile avec les librairies utilitaires event-stream, Highlandjs.js, through2, etc.
var es = require('event-stream');

vertexStream
    .pipe(es.map(function(vertex, callback) {
        vertex.fromNode = true;
        callback(null, vertex);
    }))
    .pipe(es.stringify());

Gremlin en JS avec nashorn

var gremlin = require('gremlin-client');
var client = gremlin.createClient({ language: 'nashorn' });

// Expérimental: création d'une fonction dont la seule utilité
// est de récupérer son body avec Function.toString();
var script = function() {
    g.V("type", user).filter(function(it) {
        return it.get().value('name') === nameFilter;
    });
}

var s = client.stream(script, { type: 'user', nameFilter = 'Bob' });

Objectif : permettre aux développeurs JavaScript de commencer plus rapidement avec Gremlin en écrivant des requêtes dans un langage qu'ils maitrisent déjà.

Et après?

  • Créer un object-to-graph mapper (OGM/ORM) de référence en JavaScript : il faut aux bases graph ce que Mongoose est à MongoDB.
  • Améliorer le support nashorn (Java 8)
    • performance?
    • steps surchargées
  • Développer un moteur Gremlin en pur JavaScript?
  • Développer une graph db en JavaScript?

Conclusion

  • modèle générique (comme une base relationnelle)
  • modèle très proche de la façon dont le cerveau humain appréhende l'information
  • modèle idéal pour les données connectées
    • c'est-à-dire, lorsqu'il y a davantage de valeur *entre* les données que *dans* les données en elles-mêmes

Avantages

  1. apprendre à penser autrement, tant s'agissant :
    • ... de la modélisation des données
    • ... de la façon de requêter
  2. technologie récente - relativement peu d'experts

Inconvénients

Questions ?

jbmusso@gmail.com

Twitter : @jbmusso

GitHub : @gulthor

(Thanks!)

Made with Slides.com