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

Frank Neff

August 23, 2014
Tweet

More Decks by Frank Neff

Other Decks in Programming

Transcript

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

    View Slide

  2. #frosNeo4Php

    View Slide

  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

    View Slide

  4. View Slide

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

    View Slide

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

    View Slide

  7. Person Address
    Company Product
    Customer
    Relational Data

    View Slide

  8. Relational Database

    View Slide

  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

    View Slide

  10. Graph database?

    View Slide

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

    View Slide

  12. View Slide

  13. Neo4j?
    What is

    View Slide

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

    View Slide

  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

    View Slide

  16. Simple and powerful web
    interface

    View Slide

  17. Result set
    Cypher Query
    Empty Result

    View Slide

  18. Query Language
    Cypher

    View Slide

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

    View Slide

  20. Create a node

    View Slide

  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

    View Slide

  22. Create some more nodes

    View Slide

  23. Relations?

    View Slide

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

    View Slide

  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

    View Slide

  26. Creating a relation

    View Slide

  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

    View Slide

  28. Multiple creates

    View Slide

  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

    View Slide

  30. Relationship properties

    View Slide

  31. So we created a graph...

    View Slide

  32. View Slide

  33. REST API
    Using the

    View Slide

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

    View Slide

  35. Call the transactional HTTP
    endpoint using cURL

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  41. PHP
    Usage in

    View Slide

  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

    View Slide

  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();

    View Slide

  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

    View Slide

  45. Entity mapping
    using annotations

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  52. Storing entities in the graph
    database

    View Slide

  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();

    View Slide

  54. Fetching entities from the
    graph

    View Slide

  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' => '[email protected]')
    ); // Returns a collection

    View Slide

  56. Using events

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  60. Building cypher queries

    View Slide

  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

    View Slide

  62. Final thoughts...

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide