Slide 1

Slide 1 text

Playing with -[:USING]-> Frank Neff FrOSCon 2014

Slide 2

Slide 2 text

#frosNeo4Php

Slide 3

Slide 3 text

About me Frank Neff ■ Software Engineer @ YMC AG ■ Living in Zurich, Switzerland ■ Coding PHP and Java ■ Student ■ Open Source Enthusiast ■ UAV Drone Pilot ■ Hobby Photographer ■ frankneff.ch ■ ymc.ch

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

About YMC Open Source Switzerland Agile Since 2001 Conferences International Software solutions Best of swiss web

Slide 6

Slide 6 text

We're entering a new world in which data may be more important than software - Tim O'Reilly

Slide 7

Slide 7 text

Person Address Company Product Customer Relational Data

Slide 8

Slide 8 text

Relational Database

Slide 9

Slide 9 text

■ Users can be friends with other Users ■ Users can follow other Users ■ Users can write Posts ■ Users can like other Posts ■ Users can share other Posts Let’s build a social network

Slide 10

Slide 10 text

Graph database?

Slide 11

Slide 11 text

■ Graph -[:RECORDS_DATA_IN]-> Nodes ■ Nodes -[:CAN_HAVE]-> Properties ■ Nodes -[:ARE_CONNECTED_BY]-> Relations ■ Relations -[:CAN_HAVE]-> Properties

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Neo4j? What is

Slide 14

Slide 14 text

Neo4j is a highly scalable, robust (fully ACID) native graph database

Slide 15

Slide 15 text

■ Graph model for data representation ■ Reliable, with full ACID transactions ■ Scalable, up to several billion nodes/relationships/properties ■ Cypher, a human readable query language ■ REST interface or Java API Features

Slide 16

Slide 16 text

Simple and powerful web interface

Slide 17

Slide 17 text

Result set Cypher Query Empty Result

Slide 18

Slide 18 text

Query Language Cypher

Slide 19

Slide 19 text

1 CREATE (n:Person { 2 name:'Frank', title:'Software Engineer', company: 'YMC' 3 }) 4 RETURN n Create a node

Slide 20

Slide 20 text

Create a node

Slide 21

Slide 21 text

1 CREATE 2 (a:Person { 3 name:'Pascal', title:'Senior Software Engineer', 4 company: 'YMC' 5 }), 6 (b:Person { 7 name:'Manuel', title:'Software Engineer', 8 company: 'YMC' 9 }), 10 (c:Person { 11 name:'Simon', title:'Head of Web Solutions', 12 company: 'YMC' 13 }) 14 RETURN a,b,c Create some more nodes

Slide 22

Slide 22 text

Create some more nodes

Slide 23

Slide 23 text

Relations?

Slide 24

Slide 24 text

Neo4j handles relations as objects, holding: ■ source (Node) ■ target (Node) ■ properties (Key-Value Pairs)

Slide 25

Slide 25 text

1 MATCH 2 (s:`Person` { name:'Frank' }), 3 (t:`Person` { name:'Manuel' }) 4 CREATE (s)-[r:WORKS_WITH]->(t) 5 RETURN s,t,r Creating a relation

Slide 26

Slide 26 text

Creating a relation

Slide 27

Slide 27 text

1 MATCH (me:Person) 2 WHERE me.name = 'Frank' 3 CREATE (ymc:Company { name:'YMC', business:'IT' }) 4 CREATE (me)-[relation:WORKS_AT]->(ymc) 5 RETURN me,ymc,relation; Multiple creates

Slide 28

Slide 28 text

Multiple creates

Slide 29

Slide 29 text

1 MATCH 2 (me:Person {name:'Frank'}), 3 (ymc:Company { name:'YMC'}) 4 CREATE (me)-[worksat:WORKS_AT {since:1291186800}]->(ymc) 5 RETURN me,worksat,ymc; Relationship properties

Slide 30

Slide 30 text

Relationship properties

Slide 31

Slide 31 text

So we created a graph...

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

REST API Using the

Slide 34

Slide 34 text

■ (Almost) all features available ■ Works out of the box ■ JSON ■ Fast ■ Transactional HTTP endpoint to run cypher queries

Slide 35

Slide 35 text

Call the transactional HTTP endpoint using cURL

Slide 36

Slide 36 text

POST http://localhost:7474/db/data/transaction Accept: application/json; charset=UTF-8 Content-Type: application/json { "statements" : [ { "statement" : "CREATE (n {props}) RETURN n", "parameters" : { "props" : { "name" : "My Node" } } } ] } Creating a node Request

Slide 37

Slide 37 text

200 OK Content-Type: application/json { "results" : [ { "columns" : [ "id(n)" ], "data" : [ { "row" : [ { "name" : "My Node" } ] } ] } ], "errors" : [ ] } Creating a node Response

Slide 38

Slide 38 text

Executing Cypher queries POST http://localhost:7474/db/data/cypher Accept: application/json; charset=UTF-8 Content-Type: application/json { "query" : "MATCH (x {name: 'I'})-[r]->(n) RETURN type(r), n.name, n.age", "params" : { } } Executing Cypher queries Request

Slide 39

Slide 39 text

Executing Cypher queries Executing Cypher queries 200 OK Content-Type: application/json { "columns" : [ "type(r)", "n.name", "n.age" ], "data" : [ [ "know", "him", 25 ], [ "know", "you", null ] ] } Response

Slide 40

Slide 40 text

docs.neo4j.org More about neo4j, cypher and graph databases...

Slide 41

Slide 41 text

PHP Usage in

Slide 42

Slide 42 text

PHP Wrapper for the Neo4j graph database REST interface everyman/neo4jphp ■ Written in PHP ■ Abstracts cURL requests behind a wrapper ■ Installation using GitHub / Composer ■ Easy to use ■ Implemented in many other projects ■ github.com/jadell/neo4jphp

Slide 43

Slide 43 text

// autoloading require('vendor/autoload.php'); // Connecting to the default port 7474 on localhost $client = new Everyman\Neo4j\Client(); // create a new node $arthur = $client->makeNode(); $arthur->setProperty('name', 'Frank') ->setProperty('title', 'Software Engineer') ->setProperty('company', 'YMC') ->save(); // get ID from Neo4j $arthurId = $arthur->getId();

Slide 44

Slide 44 text

Doctrine2-style entity mapper for Neo4j graph database hirevoice/neo4jphp-ogm ■ Written in PHP ■ Provides entity mapping using annotations ■ Installation using GitHub / Composer ■ Similar to Doctrine ORM ■ Implements doctrine/common ■ github.com/lphuberdeau/Neo4j-PHP-OGM

Slide 45

Slide 45 text

Entity mapping using annotations

Slide 46

Slide 46 text

namespace Entity; use HireVoice\Neo4j\Annotation as OGM; /** * @OGM\Entity */ class User { /** * @OGM\Auto */ protected $id; /** * @OGM\Property * @OGM\Index */ protected $fullName; }

Slide 47

Slide 47 text

■ Entity ■ Auto ■ Porperty ■ Index ■ ManyToOne ■ ManyToMany Available annotations

Slide 48

Slide 48 text

■ Entity ■ Auto ■ Porperty ■ Index ■ ManyToOne ■ ManyToMany use HireVoice\Neo4j\Annotation as OGM; /** * @OGM\Entity( * repositoryClass="Repo\UserRepository", * labels="Location,City" * ) */ class MyEntityWithCustomRepositoryAndLabels { // definition } Available annotations

Slide 49

Slide 49 text

■ Entity ■ Auto ■ Porperty ■ Index ■ ManyToOne ■ ManyToMany use HireVoice\Neo4j\Annotation as OGM; class MyEntity { /** * @OGM\Property(format="date") */ protected $releaseDate; } Available annotations

Slide 50

Slide 50 text

■ Entity ■ Auto ■ Porperty ■ Index ■ ManyToOne ■ ManyToMany use HireVoice\Neo4j\Annotation as OGM; class MyEntity { /** * @OGM\Property * @OGM\Index */ protected $name; } Available annotations

Slide 51

Slide 51 text

■ Entity ■ Auto ■ Porperty ■ Index ■ ManyToOne ■ ManyToMany use HireVoice\Neo4j\Annotation as OGM; class MyEntity { /** * @OGM\ManyToOne(relation="acts-in") */ protected $mainActor; } Available annotations

Slide 52

Slide 52 text

Storing entities in the graph database

Slide 53

Slide 53 text

$em = // Let's assume the entity manager is initialized in $em $repo = $em->getRepository('Entity\\User'); // The repository uses magic functions to search in indexed fields $john = $repo->findOneByFullName('John Doe'); $jane = new User; $jane->setFullName('Jane Doe'); $jane->addFollow($john); $em->persist($jane); $em->flush();

Slide 54

Slide 54 text

Fetching entities from the graph

Slide 55

Slide 55 text

$em = // Let's assume the entity manager is initialized in $em $repository = $em->getRepository('Entity\\User'); // Find a User by a specific field $user = $repository->findOneByFullName('superman'); // Returns a User object // Find some users by a specific field $usersFromFrance = $repository->findByCountry('FR'); // Returns a collection // Find one User with more than one criteria $nonActiveWithSuchEmail = $repository->findOneBy(array( 'status' => 'idle', 'email' => '[email protected]') ); // Returns a collection

Slide 56

Slide 56 text

Using events

Slide 57

Slide 57 text

use HireVoice\Neo4j\Event as Events; class PrePersistListener { public function prePersist(Events\PrePersist $event) { $entity = $event->getEntity(); // do your stuff here... } } Create event listener

Slide 58

Slide 58 text

use \Doctrine\Common\EventManager; $eventManager = new EventManager(); $listener = new PrePersistListener(); $eventManager->addEventListener( array('prePersist'), // array of all listened events $listener // instance of your event listener ); $entityManager->setEventManager($eventManager); Create event manager

Slide 59

Slide 59 text

■ prePersist - Fires before an entity is persisted ■ postPersist - Fires after an entity is persisted ■ preRelationCreate - Fires before a relation is created ■ postRelationCreate - Fires after a relation is created ■ preStmtExecute - Fires before a statement (query) is executed ■ postStmtExecute - Fires after a statement (query) is executed ■ preRemove - Fires before an entity is removed ■ postRemove - Fires after an entity is removed ■ preRelationRemove - Fires before a relation is removed ■ postRelationRemove - Fires after a relation is removed Available events

Slide 60

Slide 60 text

Building cypher queries

Slide 61

Slide 61 text

// $list is a collection of User objects $em = $this->get('hirevoice.neo4j.entity_manager'); $repo = $em->getRepository('Entity\\User'); $john = $repo->findOneByFullName('John Doe'); $list = $em->createCypherQuery() ->startWithNode('john', $john) ->match('john -[:follow]-> followedBy <-[:follow]- similarInterest') ->match('similarInterest -[:follow]-> potentialMatch') ->end('potentialMatch', 'count(*)') ->order('count(*) DESC') ->limit(10) ->getList(); Collection of entities Follow multiple relations Get em and repo, e.g. from Symfony DIC

Slide 62

Slide 62 text

Final thoughts...

Slide 63

Slide 63 text

■ Not recommended for large datasets ○ Streaming not supported ○ Memory exhaustion ■ Not feature complete yet ○ Graph traversals ○ Relation properties ■ Small community / few maintainers OGM drawbacks

Slide 64

Slide 64 text

■ Neo4j ○ ...is the most common graph database ○ fast ○ actively maintained ○ big community ■ PHP ○ ...is the most common scripting language for the web ○ widely used ○ big community ○ other great persistence libs in PHP to learn from Neo4j and PHP

Slide 65

Slide 65 text

■ Join forces ■ Spread the word ■ Contribute ○ github.com/neoxygen ○ neo4j.org/develop/php

Slide 66

Slide 66 text

Web Solutions Big Data Analytics Mobile Thank you @frank_neff www.frankneff.ch www.ymc.ch github.com/frne speakerdeck. com/frne