$30 off During Our Annual Pro Sale. View Details »

Graph Databases and PHP

Graph Databases and PHP

Traditional relational databases — ironically — are not that good at the complex relationships some modern applications need.

Multiple joins and complex sub-queries can gradually take a toll on performance.

Graph Databases, on the other hand, are all about relationships. In this talk we will look at using the popular Neo4j graph database with PHP to build efficient relational data for OmNomHub: not your average recipe site.

Michelle Sanver

February 18, 2017
Tweet

More Decks by Michelle Sanver

Other Decks in Programming

Transcript

  1. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4J is
    AWESOME

    View Slide

  2. (Michelle)-[:LOVES]->(Neo4j) @michellesanver

    View Slide

  3. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    WIIIIIIIE \o/
    “Learn the most by
    sharing your knowledge
    with others” - @coderabbi

    View Slide

  4. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    This talk is entry-
    level.

    View Slide

  5. (Michelle)-[:LOVES]->(Neo4j) @michellesanver

    View Slide

  6. (Michelle)-[:LOVES]->(Neo4j) @michellesanver

    View Slide

  7. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Michelle Sanver

    View Slide

  8. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Michelle Sanver
    Body Text
    President of PHPWomen

    View Slide

  9. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Michelle Sanver
    Accent(s)!?

    View Slide

  10. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Michelle Sanver
    Body Text

    View Slide

  11. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    I’m not a drupal
    developer.

    View Slide

  12. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    How I got into
    Neo4j

    View Slide

  13. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/

    View Slide

  14. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    Graph theory has
    been studied since
    Leonard Euler’s
    Bridges 1736

    View Slide

  15. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    Body Text

    View Slide

  16. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/

    View Slide

  17. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    Graphs are really just connected
    data… They are everywhere

    View Slide

  18. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/

    View Slide

  19. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    It’s modern.

    View Slide

  20. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    Facebook open graph

    View Slide

  21. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs \o/
    A graph is an easy way to visualise connected data.
    Michelle Graphs
    likes

    View Slide

  22. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Relational question:
    Average age of everyone in this list?
    Graph question:
    Who in here is likely going to the next DrupalCon?

    View Slide

  23. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Relational databases have tables
    Recipes

    View Slide

  24. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Tables have relationships
    Recipes Groups

    View Slide

  25. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Which causes a join table…
    Recipes Groups
    RecipeToGroup

    View Slide

  26. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    You query via the table
    Recipes Groups
    RecipeToGroup

    View Slide

  27. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Imagine having *actual* relations
    Pasta group Spaghetti Italian group

    View Slide

  28. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Spaghetti Pasta group
    Italian group
    Recipes Groups
    RecipeToGroup
    Spaghetti:Italian
    Spaghetti:Pasta
    Pasta group Spaghetti Italian group

    View Slide

  29. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Relational databases have a structure

    View Slide

  30. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Neo4j has a flexible schema

    View Slide

  31. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    A big query.
    The EAV model.

    View Slide

  32. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    SET @entityid = '3';
    SELECT ea.attribute_id,
    ea.attribute_code, eav.value AS
    'value', 'varchar' AS 'type'
    FROM catalog_category_entity e
    JOIN
    catalog_category_entity_varchar
    eav
    ON e.entity_id = eav.entity_id
    JOIN eav_attribute ea
    ON eav.attribute_id =
    ea.attribute_id
    WHERE e.entity_id = @entityid
    UNION
    SELECT ea.attribute_id,
    ea.attribute_code, eav.value
    AS 'value', 'int' AS 'type'
    FROM
    catalog_category_entity e
    JOIN
    catalog_category_entity_int
    eav
    ON e.entity_id = eav.entity_id
    JOIN eav_attribute ea
    ON eav.attribute_id =
    ea.attribute_id
    WHERE e.entity_id = @entityid
    UNION

    View Slide

  33. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    SELECT ea.attribute_id,
    ea.attribute_code, eav.value AS 'value',
    'decimal' AS 'type'
    FROM catalog_category_entity e
    JOIN catalog_category_entity_decimal
    eav
    ON e.entity_id = eav.entity_id
    JOIN eav_attribute ea
    ON eav.attribute_id = ea.attribute_id
    WHERE e.entity_id = @entityid
    UNION
    selecting ea.attribute_id, ea.attribute_code, eav.value AS 'value', 'datetim
    'type'
    FROM catalog_category_entity e
    JOIN catalog_category_entity_datetime eav
    ON e.entity_id = eav.entity_id
    JOIN eav_attribute ea
    ON eav.attribute_id = ea.attribute_id
    WHERE e.entity_id = @entityid
    UNION
    SELECT ea.attribute_id, ea.attribute_code, eav.value AS 'value', 'text' AS
    FROM catalog_category_entity e
    JOIN catalog_category_entity_text eav
    ON e.entity_id = eav.entity_id
    JOIN eav_attribute ea
    ON eav.attribute_id = ea.attribute_id
    WHERE e.entity_id = @entityid

    View Slide

  34. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Having a flexible database
    with a schema costs a lot.

    View Slide

  35. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    For modern complex data…

    View Slide

  36. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs vs. Relational databases
    Would you still pick a relational
    structure?

    View Slide

  37. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    neo4j.com

    View Slide

  38. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Java Based

    View Slide

  39. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Open Source!
    github.com/neo4j

    View Slide

  40. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Meetups everywhere
    neo4j.meetup.com

    View Slide

  41. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Graphs have…

    View Slide

  42. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    ( Nodes )

    View Slide

  43. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    (Node) { Properties }
    As many as you want
    Name:
    Michelle
    Nick:
    geekie
    Name:
    Cees-Jan
    Nick:
    WyriHaximus

    View Slide

  44. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Nick:
    geekie
    Nick:
    WyriHaximus
    knows
    (Node) [ Relationships ]
    As many as you want

    View Slide

  45. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Labels
    Nick:
    geekie
    Label: Person

    View Slide

  46. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Indexes for easy lookup

    View Slide

  47. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Common named graphs

    View Slide

  48. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Common named graphs
    Local McLaughlin graph

    View Slide

  49. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    Common named graphs
    Diamond Butterfly Bull
    Franklin Tutte Wagner

    View Slide

  50. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Graphs and Neo4j
    You can make art out of your DB.
    (Don’t, or do?)

    View Slide

  51. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    An idea for a different
    recipe website

    View Slide

  52. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Like GitHub but for recipes!

    View Slide

  53. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Fork a recipe

    View Slide

  54. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    See all forks

    View Slide

  55. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Send change requests

    View Slide

  56. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Join groups and share recipe
    collections among them

    View Slide

  57. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Have your own private recipe
    collections

    View Slide

  58. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Search similar recipes
    (This is a part where the graph structure shines)

    View Slide

  59. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    Honestly… It’s a pet project

    View Slide

  60. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture

    View Slide

  61. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Disks
    File System Cache
    Record Files
    Object Cache
    Cypher
    Core API
    Traversal API
    Transaction
    Management
    Transaction Log

    View Slide

  62. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Disks
    File System Cache
    Record Files
    Object Cache
    Cypher
    Core API
    Traversal API
    Transaction
    Management
    Transaction Log

    View Slide

  63. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Disks
    File System Cache
    Record Files
    Object Cache
    Cypher
    Core API
    Traversal API
    Transaction
    Management
    Transaction Log

    View Slide

  64. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Disks
    File System Cache
    Record Files
    Object Cache
    Cypher
    Core API
    Traversal API
    Transaction
    Management
    Transaction Log

    View Slide

  65. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture

    View Slide

  66. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Disks
    File System Cache
    Record Files
    Object Cache
    Cypher
    Core API
    Traversal API
    Transaction
    Management
    Transaction Log

    View Slide

  67. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Cypher and
    Browser

    View Slide

  68. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Cypher
    Cypher: SQL for graph databases.

    View Slide

  69. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Cypher
    )
    Parentheses means nodes
    (Or hugs)
    (

    View Slide

  70. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Cypher
    }
    Curly braces means
    properties
    {

    View Slide

  71. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Cypher
    ]
    Square brackets means
    relationships
    [

    View Slide

  72. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Browser
    Makes it easy to visualise and query
    the data.

    View Slide

  73. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Browser
    Let’s learn cypher in the browser!

    View Slide

  74. DEMO: Cypher and Browser
    (Michelle)-[:LOVES]->(Neo4j) @michellesanver

    View Slide

  75. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j architecture
    Neostore File Storage

    View Slide

  76. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Several different store files

    View Slide

  77. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Each store has specific data

    View Slide

  78. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Nodes
    neostore.nodestore.db

    9 bytes

    View Slide

  79. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Fixed size == FAST

    View Slide

  80. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Relationships
    neostore.relationshipstore.
    db

    33 bytes

    View Slide

  81. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neostore
    Properties
    neostore.propertystore.db

    neostore.propertystore.db.
    index

    neostore.propertystore.db.
    strings

    neostore.propertystore.db.
    arrays

    View Slide

  82. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Hardware
    matters!

    View Slide

  83. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Caching in memory,
    or filesystem

    View Slide

  84. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP

    View Slide

  85. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    There is an actively maintained
    Drupal module for Drupal 7 and 8.
    https://www.drupal.org/project/neo4j

    View Slide

  86. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    As we saw
    There’s a REST interface!

    View Slide

  87. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    GraphAware PHP Client
    https://github.com/graphaware/neo4j-php-client

    View Slide

  88. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    $client = ClientBuilder::create()

    ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')

    ->build();

    $query = "MATCH (n:User) RETURN n";

    $result = $client->run($query);


    foreach ($result->getRecords() as $record) {

    echo(count($record->value('name'));

    }


    View Slide

  89. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    $client = ClientBuilder::create()

    ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')

    ->build();

    $query = "MATCH (n:User) RETURN n";

    $result = $client->run($query);


    foreach ($result->getRecords() as $record) {

    echo(count($record->value('name'));

    }


    View Slide

  90. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    $client = ClientBuilder::create()

    ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')

    ->build();

    $query = "MATCH (n:User) RETURN n";

    $result = $client->run($query);


    foreach ($result->getRecords() as $record) {

    echo(count($record->value('name'));

    }


    View Slide

  91. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    $client = ClientBuilder::create()

    ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')

    ->build();

    $query = "MATCH (n:User) RETURN n";

    $result = $client->run($query);


    foreach ($result->getRecords() as $record) {

    echo(count($record->value('name'));

    }


    View Slide

  92. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    GraphAware also released an OGM

    View Slide

  93. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    /**

    * @OGM\GraphId()

    * @var int

    */

    protected $id;


    /**

    * @OGM\Property(type="string")

    * @var string

    */

    protected $recipeName;


    /**

    * @OGM\Relationship(type="FORKED", direction="OUTGOING",
    targetEntity="User", collection=true)

    * @var ArrayCollection|User[]

    */

    protected $users;

    View Slide

  94. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    /**

    * @OGM\GraphId()

    * @var int

    */

    protected $id;


    /**

    * @OGM\Property(type="string")

    * @var string

    */

    protected $recipeName;


    /**

    * @OGM\Relationship(type="FORKED", direction="OUTGOING",
    targetEntity="User", collection=true)

    * @var ArrayCollection|User[]

    */

    protected $users;

    View Slide

  95. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    /**

    * @OGM\GraphId()

    * @var int

    */

    protected $id;


    /**

    * @OGM\Property(type="string")

    * @var string

    */

    protected $recipeName;


    /**

    * @OGM\Relationship(type="FORKED", direction="OUTGOING",
    targetEntity="User", collection=true)

    * @var ArrayCollection|User[]

    */

    protected $users;

    View Slide

  96. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    /**

    * @OGM\GraphId()

    * @var int

    */

    protected $id;


    /**

    * @OGM\Property(type="string")

    * @var string

    */

    protected $recipeName;


    /**

    * @OGM\Relationship(type="FORKED", direction="OUTGOING",
    targetEntity="User", collection=true)

    * @var ArrayCollection|User[]

    */

    protected $users;

    View Slide

  97. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    $user = $em->getRepository(User::class)-
    >findOneBy('name', 'Michelle');

    View Slide

  98. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Neo4j in PHP
    It is well documented
    https://neo4j.com/developer/php/
    https://github.com/graphaware/neo4j-php-client
    https://github.com/graphaware/neo4j-php-ogm

    View Slide

  99. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub
    The possible Future

    View Slide

  100. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub: The Future
    Connecting users
    “You both like”

    View Slide

  101. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub: The Future
    Connecting recipes
    “These have similar ingredients and
    user base”

    View Slide

  102. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub: The Future
    Being smart
    “You might like”

    View Slide

  103. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub: The Future
    Being smart
    Smart recipe collections!

    View Slide

  104. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    OmNomHub: The Future
    Being creepy
    “Don’t like meat huh?”

    View Slide

  105. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Wrapup

    View Slide

  106. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Wrapup
    Graphs are everywhere

    View Slide

  107. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Wrapup
    They make it easy to connect data

    View Slide

  108. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Wrapup
    Easier to be creepy <3

    View Slide

  109. Resources
    (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    neo4j.org/learn
    https://neo4j.com/developer/php/
    https://www.drupal.org/project/neo4j

    View Slide

  110. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Thank you!

    View Slide

  111. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    Questions?

    View Slide

  112. (Michelle)-[:LOVES]->(Neo4j) @michellesanver
    How would you
    use it?

    View Slide