Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Plaing with Neo4j -[:USING]-> PHP

Plaing with Neo4j -[:USING]-> PHP

Slides from my talk at FrOSCon 2014

52034cfb48ca73e13e130f2711ec41f0?s=128

Frank Neff

August 23, 2014
Tweet

Transcript

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

  2. #frosNeo4Php

  3. 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
  4. None
  5. About YMC Open Source Switzerland Agile Since 2001 Conferences International

    Software solutions Best of swiss web
  6. We're entering a new world in which data may be

    more important than software - Tim O'Reilly
  7. Person Address Company Product Customer Relational Data

  8. Relational Database

  9. ▪ 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
  10. Graph database?

  11. ▪ Graph -[:RECORDS_DATA_IN]-> Nodes ▪ Nodes -[:CAN_HAVE]-> Properties ▪ Nodes

    -[:ARE_CONNECTED_BY]-> Relations ▪ Relations -[:CAN_HAVE]-> Properties
  12. None
  13. Neo4j? What is

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

    database
  15. ▪ 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
  16. Simple and powerful web interface

  17. Result set Cypher Query Empty Result

  18. Query Language Cypher

  19. 1 CREATE (n:Person { 2 name:'Frank', title:'Software Engineer', company: 'YMC'

    3 }) 4 RETURN n Create a node
  20. Create a node

  21. 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
  22. Create some more nodes

  23. Relations?

  24. Neo4j handles relations as objects, holding: ▪ source (Node) ▪

    target (Node) ▪ properties (Key-Value Pairs)
  25. 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
  26. Creating a relation

  27. 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
  28. Multiple creates

  29. 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
  30. Relationship properties

  31. So we created a graph...

  32. None
  33. REST API Using the

  34. ▪ (Almost) all features available ▪ Works out of the

    box ▪ JSON ▪ Fast ▪ Transactional HTTP endpoint to run cypher queries
  35. Call the transactional HTTP endpoint using cURL

  36. 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
  37. 200 OK Content-Type: application/json { "results" : [ { "columns"

    : [ "id(n)" ], "data" : [ { "row" : [ { "name" : "My Node" } ] } ] } ], "errors" : [ ] } Creating a node Response
  38. 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
  39. 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
  40. docs.neo4j.org More about neo4j, cypher and graph databases...

  41. PHP Usage in

  42. 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
  43. // 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();
  44. 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
  45. Entity mapping using annotations

  46. namespace Entity; use HireVoice\Neo4j\Annotation as OGM; /** * @OGM\Entity */

    class User { /** * @OGM\Auto */ protected $id; /** * @OGM\Property * @OGM\Index */ protected $fullName; }
  47. ▪ Entity ▪ Auto ▪ Porperty ▪ Index ▪ ManyToOne

    ▪ ManyToMany Available annotations
  48. ▪ 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
  49. ▪ Entity ▪ Auto ▪ Porperty ▪ Index ▪ ManyToOne

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

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

    ▪ ManyToMany use HireVoice\Neo4j\Annotation as OGM; class MyEntity { /** * @OGM\ManyToOne(relation="acts-in") */ protected $mainActor; } Available annotations
  52. Storing entities in the graph database

  53. $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();
  54. Fetching entities from the graph

  55. $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' => 'superman@chucknorris.com') ); // Returns a collection
  56. Using events

  57. use HireVoice\Neo4j\Event as Events; class PrePersistListener { public function prePersist(Events\PrePersist

    $event) { $entity = $event->getEntity(); // do your stuff here... } } Create event listener
  58. 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
  59. ▪ 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
  60. Building cypher queries

  61. // $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
  62. Final thoughts...

  63. ▪ Not recommended for large datasets ◦ Streaming not supported

    ◦ Memory exhaustion ▪ Not feature complete yet ◦ Graph traversals ◦ Relation properties ▪ Small community / few maintainers OGM drawbacks
  64. ▪ 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
  65. ▪ Join forces ▪ Spread the word ▪ Contribute ◦

    github.com/neoxygen ◦ neo4j.org/develop/php
  66. Web Solutions Big Data Analytics Mobile Thank you @frank_neff www.frankneff.ch

    www.ymc.ch github.com/frne speakerdeck. com/frne