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.

01da6d807a29ad6d49801c0157518148?s=128

Michelle Sanver

February 18, 2017
Tweet

Transcript

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

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

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

    knowledge with others” - @coderabbi
  4. (Michelle)-[:LOVES]->(Neo4j) @michellesanver This talk is entry- level.

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

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

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

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

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

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

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

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

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

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

    Leonard Euler’s Bridges 1736
  15. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs \o/ Body Text

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

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

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

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

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

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

    to visualise connected data. Michelle Graphs likes
  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?
  23. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs vs. Relational databases Relational databases have tables

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

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

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

    table Recipes Groups RecipeToGroup
  27. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs vs. Relational databases Imagine having *actual* relations

    Pasta group Spaghetti Italian group
  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
  29. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs vs. Relational databases Relational databases have a

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

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

    EAV model.
  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
  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
  34. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs vs. Relational databases Having a flexible database

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

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

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

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

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

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

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

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

  43. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs and Neo4j (Node) { Properties } As

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

    (Node) [ Relationships ] As many as you want
  45. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs and Neo4j Labels Nick: geekie Label: Person

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

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

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

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

    Bull Franklin Tutte Wagner
  50. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Graphs and Neo4j You can make art out

    of your DB. (Don’t, or do?)
  51. (Michelle)-[:LOVES]->(Neo4j) @michellesanver OmNomHub An idea for a different recipe website

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

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

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

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

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

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

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

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

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

  61. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Neo4j architecture Disks File System Cache Record Files

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

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

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

    Object Cache Cypher Core API Traversal API Transaction Management Transaction Log
  65. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Neo4j architecture

  66. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Neo4j architecture Disks File System Cache Record Files

    Object Cache Cypher Core API Traversal API Transaction Management Transaction Log
  67. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Cypher and Browser

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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
  86. (Michelle)-[:LOVES]->(Neo4j) @michellesanver Neo4j in PHP As we saw There’s a

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

  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'));
 }

  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'));
 }

  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'));
 }

  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'));
 }

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

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

  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
  99. (Michelle)-[:LOVES]->(Neo4j) @michellesanver OmNomHub The possible Future

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

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

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

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

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

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

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

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

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

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

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

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

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