Neo4j - Reloaded !
Neo4j
● Présentation générale
● Le graphe
● CYPHER
● Se connecter à Neo4j (Java & REST)
● Extensions
● Ecosystème
Neo4j
Présentation générale
Présentation Générale
● Version stable : 2.3.1
● Dernière version : 3.0.0.M01
● Base de données NoSQL orientée Graphe
● Modèle de cohérence ACID
● HA
● Console WEB ou Shell
Neo4j n'est pas...
● Un outil de visualisation
Mais Neo4j permet aussi de...
● Visualiser les données
Neo4j
Le graphe
Le graphe
● Graphe, nœuds, relations, propriétés
● Les relations organisent les nœuds dans le graphe
Le graphe
Graphe orienté (digraphe) ou non orienté :
Le graphe
Complet, connexe ou à composantes connexes :
Le graphe
Cyclique ou acyclique :
Le graphe
● Cela induit...
...pas de notion de clés étrangères
Le graphe
● Neo4j stocke nativement les données dans un graphe
● Ce graphe est orienté
● Les relations sont typées
● Permet d'accéder à la donnée locale (voisinage)
Neo4j
CYPHER
CYPHER
Langage d'interrogation natif Neo4j
● MATCH (je retrouve)
● RETURN (et je retourne pour résultat...)
MATCH (n) RETURN n
CYPHER – Pattern Matching
Langage d'interrogation natif Neo4j
● MATCH (je retrouve)
● RETURN (et je retourne pour résultat...)
MATCH modele_de_chemin RETURN elements_de_résultats
CYPHER – Pattern Matching
MATCH ()--()
CYPHER – Pattern Matching
MATCH (A)--(B)
CYPHER – Pattern Matching
MATCH (A)-->(B)
CYPHER – Pattern Matching
MATCH (A)<--(B)-->(C)
CYPHER – Pattern Matching
MATCH (A)-->(B)<--(C) , (D)-->(B)
CYPHER – Pattern Matching
MATCH (A)-[:CONNAIT]->(B)
CYPHER – Pattern Matching
MATCH (A)-[:*1..3]->(E)
CYPHER – Where
● MATCH (je retrouve)
● WHERE (prédicat)
● RETURN (et je retourne pour résultat...)
MATCH modele_de_cheminWHERE prédicat RETURN elements_de_résultats
CYPHER – Where
MATCH (n)WHERE n.nom = 'Sylvain'RETURN n
MATCH (n {nom :'Sylvain'})RETURN n
CYPHER – Labels
MATCH (n:Personne)RETURN n
MATCH (n:Personne:Developpeur)RETURN n
MATCH (n:Personne:Developpeur {nom :'Sylvain'})RETURN n
CYPHER – Exemple : Movie db
MATCH (n)-[r]->(m) RETURN DISTINCT labels (n), type (r), labels (m)
Retrouver les relations entre les différents types de nœuds :
MATCH (n:Person)-[r:ACTED_IN]->(m:Movie) RETURN m.title as Film, m.released as sortie, collect (n.name) ORDER BY sortie DESC
Neo4j
Se connecter à Neo4j
Se connecter à neo4j
– Embedded
– REST
– (et bientôt BOLT)
– JDBC
Embedded
● Java
● Mémoire JVM partagée
Votre application
Graphe
Api Neo4j
Embedded
● Exemple : <dependency><groupId>org.neo4j</groupId> <artifactId>neo4j</artifactId><version>2.3.0</version></dependency>
Graphe
final GraphDatabaseFactory factory = new GraphDatabaseFactory();final File dbPath = new File("./neograph.graphdb");
GraphDatabaseService graphe = factory.newEmbeddedDatabase(dbPath);
Embedded
GraphDatabaseService graph = factory.newEmbeddedDatabaseBuilder(dbPath) .loadPropertiesFromFile("custom.properties") .newGraphDatabase();
Runtime.getRuntime() .addShutdownHook(new Thread(){ public void run(){ graph.shutdown(); } } );
Java API
try ( Transaction tx = graph.beginTx() ){ final Node n1 = graph.createNode(); n1.setProperty("name", "Sylvain");
tx.success();}
Java API
try ( Transaction tx = graph.beginTx() ){ final Node n1 = graph.createNode(); n1.setProperty("name", "Sylvain");
final Node n2 = graph.createNode();n2.setProperty("name", "Philippe");
RelationshipType relType = DynamicRelationshipType.withName("KNOWS");
n1.createRelationshipTo(n2,relType);
tx.success();}
OGM (Object Graph Mapper) – v1.1.3
@NodeEntitypublic class Person {
@GraphId private Long id;
private String name; @Relationship(type = "ACTS_IN", direction = "OUTGOING") private Set<Movie> movies = new HashSet<>();
public Person() { }
public void actsIn(Movie movie) { movies.add(movie); movie.getActors().add(this); }
OGM (Object Graph Mapper)
@NodeEntitypublic class Movie {
@GraphId private Long id;
private String title; private int released;
@Relationship(type = "ACTS_IN", direction = "INCOMING") Set<Person> actors = new HashSet<>();
public Movie() { }
public Movie(String title, int year) { this.title = title; this.released = year; }
OGM (Object Graph Mapper)
SessionFactory sessionFactory = new SessionFactory("org.gomsource.meetup.embedded.ogm");
Session session = sessionFactory.openSession("http://localhost:7474","neo4j","root");
Movie movie = new Movie("The Matrix", 1999);
Person keanu = new Person();keanu.setName("Keanu Reeves");keanu.actsIn(movie);
Person carrie = new Person();carrie.setName("Carrie-Ann Moss");carrie.actsIn(movie);
session.save(movie);
public interface MovieRepository extends GraphRepository<Movie>{
Movie findByTitle (String title);}
public interface PersonRepository extends GraphRepository<Person>{
@Query ( "MATCH (p:Person)-[:ACTED_IN]->(m:Movie{title:{0}}) RETURN p") Set<Person> getActorsByMovie (String movieTitle);}
Spring Data (SDN)
Spring Data (SDN)@Servicepublic class MovieService {
@Resource MovieRepository movieRepository;
@Resource PersonRepository personRepository;
public MovieService() { }
public Set<Person> getActorsFromFilm (String title) { Movie m = movieRepository.findByTitle(title); return m.getActors(); }
public Set<Person> getMatrixActors () { Set<Person> p = personRepository.getActorsByMovie("The Matrix"); return p; }}
Spring Data (SDN)
@Configuration@EnableNeo4jRepositories("org.gomsource.meetup.sdn")@EnableTransactionManagement@ComponentScan("org.gomsource.meetup")
public class PersistenceContext extends Neo4jConfiguration { @Override public SessionFactory getSessionFactory() { return new SessionFactory("org.gomsource.meetup"); } @Bean public Neo4jServer neo4jServer() { return new RemoteServer("http://neo4j:root@localhost:7474"); }}
Spring Data (SDN)
ApplicationContext ctx = new AnnotationConfigApplicationContext(PersistenceContext.class);
MovieService movieService = ctx.getBean(MovieService.class);
System.out.println(movieService.getActorsFromFilm("The Matrix"));System.out.println(movieService.getMatrixActors());
JDBC
public static void main (String args[]){try { // Make sure Neo4j Driver is registered Class.forName("org.neo4j.jdbc.Driver");
// Connect Connection con = DriverManager.getConnection("jdbc:neo4j://localhost:7474/","neo4j","root");
// Querying Statement stmt = con.createStatement() ResultSet rs = stmt.executeQuery("MATCH (n:Person) RETURN n.name"); while(rs.next()) { System.out.println(rs.getString("n.name")); }
}
BOLT
Driver driver = GraphDatabase.driver("bolt://localhost:7687");
try (Session session = driver.session()) {
Result rs = session.run( "MATCH (:Person {name:{nameP}})-[:ACTED_IN]->(m:Movie)" + " RETURN m", Values.parameters("nameP","Keanu Reeves"));
while (rs.next()) { System.out.println(rs.get("m").get("title").javaString()); }}
Neo4j
REST (Transactional Endpoint)
REST
● Accéder au service racine
curl -X GET --user neo4j:root http://localhost:7474/db/data/
{ "extensions" : { }, "node" : "http://localhost:7474/db/data/node", "node_index" : "http://localhost:7474/db/data/index/node", "relationship_index" : "http://localhost:7474/db/data/index/relationship", "extensions_info" : "http://localhost:7474/db/data/ext", "relationship_types" : "http://localhost:7474/db/data/relationship/types", "batch" : "http://localhost:7474/db/data/batch", "cypher" : "http://localhost:7474/db/data/cypher", "indexes" : "http://localhost:7474/db/data/schema/index", "constraints" : "http://localhost:7474/db/data/schema/constraint", "transaction" : "http://localhost:7474/db/data/transaction", "node_labels" : "http://localhost:7474/db/data/labels", "neo4j_version" : "3.0.0-M01"}
REST – service transactionnel
● Envoyer une requête CYPHER
curl -X POST --user neo4j:root -H "Content-Type:application/json" -d '{"statements" : [{"statement" : "MATCH (n)-[r]->(m) RETURN DISTINCT labels (n), type (r), labels (m)"}]}' http://localhost:7474/db/data/transaction/commit
{"results":[{ "columns":["labels (n)","type (r)","labels (m)"], "data":[ {"row":[["Person"],"ACTED_IN",["Movie"]]}, {"row":[["Person"],"PRODUCED",["Movie"]]}, {"row":[["Person"],"WROTE",["Movie"]]}, {"row":[["Person"],"DIRECTED",["Movie"]]}, {"row":[["Person"],"FOLLOWS",["Person"]]}, {"row":[["Person"],"REVIEWED",["Movie"]]}]}], "errors":[]}
REST – service transactionnel
Ouvrir et terminer une transaction :POST http://localhost:7474/db/data/transaction/commit
Ouvrir une transaction :POST http://localhost:7474/db/data/transaction
Envoyer des transactions dans une transaction connue :POST http://localhost:7474/db/data/transaction/{id_de_transaction}
Terminer une transaction connue :POST http://localhost:7474/db/data/transaction/{id_de_transaction}/commit
Annuler une transaction connue :DELETE http://localhost:7474/db/data/transaction/{id_de_transaction}
REST – service transactionnel
{ "commit":"http://localhost:7474/db/data/transaction/236/commit", "results":[{"columns":["labels (n)","type (r)","labels (m)"],"data":[ {"row":[["Person"],"ACTED_IN",["Movie"]]}, {"row":[["Person"],"PRODUCED",["Movie"]]}, {"row":[["Person"],"WROTE",["Movie"]]}, {"row":[["Person"],"DIRECTED",["Movie"]]}, {"row":[["Person"],"FOLLOWS",["Person"]]}, {"row":[["Person"],"REVIEWED",["Movie"]]}]}], "transaction":{"expires":"Sun, 06 Dec 2015 17:01:51 +0000"},"errors":[]}
curl -X POST --user neo4j:root -H "Content-Type:application/json" -d '{"statements" : [{"statement" : "MATCH (n)-[r]->(m) RETURN DISTINCT labels (n), type (r), labels (m)"}]}' http://localhost:7474/db/data/transaction
Rollback au bout de 60 Secondes
Drivers et langages
Neo4j
Extensions
Extensions
JAVA Server API
JAVA Server API + JAX-RS
Server Plugins (REST)
Unmanaged extensions (REST)
Extensions – Server Plugin
@Description ("My custom server plugin")public class MyServerPlugin extends ServerPlugin{
public MyServerPlugin() {}
@Name ("get_labels") @PluginTarget (GraphDatabaseService.class) public Representation getLabels (@Source GraphDatabaseService graphDb) {
final Iterable<Label> labels = GlobalGraphOperations.at(graphDb).getAllLabels(); final List<String> slabels = new ArrayList<String>(); for (Label label : labels) { slabels.add(label.name()); } Representation r = ListRepresentation.string(slabels); return r; }...
Extensions – Server Plugin
org.gomsource.meetup.extensions.MyServerPlugin
> { "extensions" : { "MyServerPlugin" : { "get_labels" : "http://localhost:7474/db/data/ext/MyServerPlugin/graphdb/get_labels" } }, ...
>curl --user neo4j:root http://localhost:7474/db/data
Extensions – Server Plugin
> curl -X POST --user neo4j:root http://localhost:7474/db/data/ext/MyServerPlugin/graphdb/get_labels
>[ "Movie", "Person" ]
>curl -X GET --user neo4j:root http://localhost:7474/db/data/ext/MyServerPlugin/graphdb/get_labels
>{ "extends" : "graphdb", "description" : "", "name" : "get_labels", "parameters" : [ ]}
Extensions disponibles
https://github.com/neo4j-contrib/spatial/tree/0.15-neo4j-2.3
http://maxdemarzi.com/2014/01/31/neo4j-spatial-part-1/
Neo4j - Spatial
Extensions disponibles
http://graphaware.com/
GraphAware
• Reco => Recommandation• TimeTree => Arbre de temps• UUID : générateur d'ID•
Neo4j
Ecosystème
Exemples
• Twitter : http://network.graphdemos.com/#browser•
Exemples
• Twitter : http://network.graphdemos.com/#browser•
Amazon’s Elastic Container Service (ECS).
Chaque instance : 1/4th of a CPU core and 768MB
Exemples
// Utilisateurs que j'ai mentionnéMATCH (u:User {screen_name:'SylvainRoussy'})-[p:POSTS]->(t:Tweet) -[:MENTIONS]->(m:User)WITH u,p,t,m, COUNT(m.screen_name) AS countORDER BY count DESCRETURN u,p,t,mLIMIT 10
// On se suit mutuellementMATCH(u:User {screen_name:'SylvainRoussy'})-[p:FOLLOWS]->(m:User)-[:FOLLOWS]->(u) RETURN collect(m), count (m)
Exemples
MATCH
(u:User {screen_name:'SylvainRoussy'})-[p:POSTS]->(m:Tweet)-[:TAGS]->(h:Hashtag)
WITH h, collect(m) as tweets WITH h, tweets,length (tweets) as number ORDER BY number DESC
RETURN
h,tweets, number
La Viz' JS
Problématiques :• Layout !• Nombre de noeuds affichables simultanément• Navigation (interactions)• Filtres
API Javascript :
• Sigma JS : http://sigmajs.org/• Linkurious.js :I https://github.com/Linkurious/linkurious.js• D3 JS : http://d3js.org/• Alchemy JS : http://graphalchemist.github.io/Alchemy/• Ngraph (Vivagraph) : https://github.com/anvaka/ngraph• CytoScape JS : http://js.cytoscape.org/•
•
La Viz' Produits
• GEPHI : http://gephi.github.io/• Linkurious : http://linkurio.us/• Cytoscape : http://www.cytoscape.org/• Tom Sawyer : https://www.tomsawyer.com/• Graph Commons : https://graphcommons.com/•
•
On Cloud & On Docker
• GrapheneDb : http://www.graphenedb.com/• GraphStory : https://www.graphstory.com/• Heroku : https://www.heroku.com/
https://hub.docker.com/r/neo4j/neo4j/
docker run \
--detach \
--publish=7474:7474 \ --volume=$HOME/neo4j/data:/data \
neo4j/neo4j
Des questions ?
Merci !