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

An introduction to Graph Databases in PHP, using Neo4j

An introduction to Graph Databases in PHP, using Neo4j

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

April 13, 2019
Tweet

More Decks by Michelle Sanver

Other Decks in Programming

Transcript

  1. ( @michellesanver )-[:LOVES]->(Neo4j) A graph is an easy way to

    visualise connected data. Michelle Graphs likes
  2. ( @michellesanver )-[:LOVES]->(Neo4j) (Node) { Properties } As many as

    you want Name: Michelle Nick: geekie Name: Cees-Jan Nick: WyriHaximus
  3. ( @michellesanver )-[:LOVES]->(Neo4j) Relational question: Get me all recipes for

    this user Graph question: What recipe should we recommend the user to cook next?
  4. ( @michellesanver )-[:LOVES]->(Neo4j) Relational vs. Graph (1) Spaghetti Bolognese (2)

    Pasta (1) Italian Recipes Groups RecipeToGroup recipeId:1 | groupId: 1 recipeId:1 | groupId: 2 Pasta (group) Spaghetti
 Bolognese
 (recipe) Italian (group) is_in is_in
  5. ( @michellesanver )-[:LOVES]->(Neo4j) (1) Name: Pasta … Ingredients (1) Spaghetti

    Bolognese (2) Pasta (1) Italian Recipes Groups RecipeToGroup recipeId:1 | groupId: 1 recipeId:1 | groupId: 2 IngredientId: 1 RecipeId: 1 Unit: g Amount: 500 IngredientToRecipe (2) Name: Meat … IngredientId: 2 RecipeId: 1 Unit: g Amount: 800
  6. ( @michellesanver )-[:LOVES]->(Neo4j) Pasta (group) Italian (group) is_in is_in Italian

    (group) Meat (Ingredient) Pasta (Ingredient) contains amount: 500 unit: g contains
 amount: 800 unit: g Spaghetti
 Bolognese
 (recipe)
  7. ( @michellesanver )-[:LOVES]->(Neo4j) 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
  8. ( @michellesanver )-[:LOVES]->(Neo4j) 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', 'datetime' AS '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 'type' 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
  9. ( @michellesanver )-[:LOVES]->(Neo4j) Disks File System Cache Record Files Object

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

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

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

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

    Cache Cypher Core API Traversal API Transaction Management Transaction Log
  14. ( @michellesanver )-[:LOVES]->(Neo4j) OmNomHub The future* * Maybe when my

    son moved away from home… In a land, far far away
  15. ( @michellesanver )-[:LOVES]->(Neo4j) $client = ClientBuilder::create()
 ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')
 ->build(); 


    $query = "MATCH (n:User) RETURN n.name”;
 $result = $client->run($query);
 
 foreach ($result->getRecords() as $record) {
 echo(count($record->value('name'));
 }

  16. ( @michellesanver )-[:LOVES]->(Neo4j) $client = ClientBuilder::create()
 ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')
 ->build(); 


    $query = "MATCH (n:User) RETURN n.name”;
 $result = $client->run($query);
 
 foreach ($result->getRecords() as $record) {
 echo(count($record->value('name'));
 }

  17. ( @michellesanver )-[:LOVES]->(Neo4j) $client = ClientBuilder::create()
 ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')
 ->build(); 


    $query = "MATCH (n:User) RETURN n.name”;
 $result = $client->run($query);
 
 foreach ($result->getRecords() as $record) {
 echo(count($record->value('name'));
 }

  18. ( @michellesanver )-[:LOVES]->(Neo4j) $client = ClientBuilder::create()
 ->addConnection('bolt', 'bolt://neo4j:password@localhost:7687')
 ->build(); 


    $query = "MATCH (n:User) RETURN n.name”;
 $result = $client->run($query);
 
 foreach ($result->getRecords() as $record) {
 echo(count($record->get('name'));
 }

  19. ( @michellesanver )-[:LOVES]->(Neo4j) /**
 * @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;
  20. ( @michellesanver )-[:LOVES]->(Neo4j) /**
 * @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;
  21. ( @michellesanver )-[:LOVES]->(Neo4j) /**
 * @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;
  22. ( @michellesanver )-[:LOVES]->(Neo4j) /**
 * @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;
  23. ( @michellesanver )-[:LOVES]->(Neo4j) Neo4j + PHP is well documented https://neo4j.com/developer/php/

    https://github.com/graphaware/neo4j-php-client https://github.com/graphaware/neo4j-php-ogm