SlideShare a Scribd company logo
1 of 91
Download to read offline
Leveraging the Power of
Graph Databases
in PHP
Jeremy Kendall
Atlanta PHP
April 2015
Obligatory Intro Slide
Also - New Father
What Kind of
Database?
Graphs != Charts
https://www.flickr.com/photos/markgroves/3065192499/
Graphs != Charts
http://stephenwildish.tumblr.com/post/101408321763/friday-project-witch-moral-compass
Graph Databases
• Data Model
• Nodes with properties
• Typed relationships
• Strengths
• Highly connected data
• ACID
• Weaknesses
• Paradigm shift
• Examples
• Neo4j, Titan, OrientDB
Why Care?
• All the NoSQL Joy
• Schema-less
• Semi-structured data
• Escape from JOIN Hell
• Speed
Why Care?
• Relationships have 1st class status
• Just as important as the objects they connect
• You can have properties & labels
• Multiple relationships
Why Care?
Speed
Depth MySQL Query Time Neo4j Query Time Records Returned
2 0.028 (28 MS) 0.04 ~900
3 0.213 0.06 ~999
4 10.273 0.07 ~999
5 92.613 0.07 ~999
1,000 people with an average 50 friends each
Crazy Speed
Depth MySQL Query Time Neo4j Query Time Records Returned
2 0.016 (16 MS) 0.01 ~2500
3 30.27 0.168 ~125,000
4 1543.505 1.359 ~600,000
5 Stopped after 1 hour 2.132 ~800,000
1,000,000 people with an average 50 friends each
Neo4j + Cypher
Cypher
• Neo4j’s declarative query language
• Easy to pick up
• Some clauses and concepts familiar from SQL
Simple Example
Goal
Create Some Nodes
CREATE (jk:Person { name: "Jeremy Kendall" })
CREATE (gs:Company { name: "Graph Story" })
CREATE (tn:State { name: "Tennessee" })
CREATE (memphis:City { name: "Memphis" })
CREATE (nashville:City { name: "Nashville" })
CREATE (hotchicken:Food { name: "Hot Chicken" })
CREATE (bbq:Food { name: "Barbecue" })
CREATE (photography:Hobby { name: "Photography" })
CREATE (language:Language { name: "PHP" })
// . . . snip . . .
Create Some Relationships
// . . . snip . . .
CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs),
(jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville),
(hotchicken)-[:ONLY_IN]->(nashville),
(bbq)-[:ONLY_IN]->(memphis),
(jk)-[:LOVES]->(hotchicken),
// . . . snip . . .
Create Some Relationships
// . . . snip . . .
CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs),
(jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville),
(hotchicken)-[:ONLY_IN]->(nashville),
(bbq)-[:ONLY_IN]->(memphis),
(jk)-[:LOVES]->(hotchicken),
// . . . snip . . .
Create Some Relationships
// . . . snip . . .
CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs),
(jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville),
(hotchicken)-[:ONLY_IN]->(nashville),
(bbq)-[:ONLY_IN]->(memphis),
(jk)-[:LOVES]->(hotchicken),
// . . . snip . . .
Create Some Relationships
// . . . snip . . .
CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs),
(jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville),
(hotchicken)-[:ONLY_IN]->(nashville),
(bbq)-[:ONLY_IN]->(memphis),
(jk)-[:LOVES]->(hotchicken),
// . . . snip . . .
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Example Cypher Query
MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l)
WITH p, l
MATCH (p)-[:WORKS_AT]->(j)
WITH p, l, j
MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City)
RETURN p, l, j, o
Query Result
However!
Easy to Model,
Challenging to Master
Subtle(-ish) Bug
Subtle(-ish) Bug
Neo4j + PHP
Neo4jPHP
• PHP wrapper for the Neo4j REST API
• Installable via Composer
• Used internally at Graph Story
• Used in this presentation
• Well tested
• https://packagist.org/packages/everyman/
neo4jphp
Also see: NeoClient
• Written by Neoxygen
• Alternative PHP wrapper for the Neo4j REST API
• Installable via Composer
• Accepted for internal use at Graph Story
• Well tested
• https://packagist.org/packages/neoxygen/neoclient
Connecting
$neo4jClient = new EverymanNeo4jClient(
‘yourgraph.example.com’,
7473
);
$neo4jClient->getTransport()
->setAuth('username', 'password')
->getTransport()->useHttps();
Creating a Node and Label
$node = new Node($neo4jClient);
$label = $neo4jClient->makeLabel('Person');
$node->setProperty('name', ‘Jeremy Kendall');
$node->save()->addLabels(array($label));
Searching
// Searching for a label by property
$label = $neo4jClient->makeLabel('Person');
$nodes = $label->getNodes('name', $name);
Querying (Cypher)
$queryString =
'MATCH (p:Person { name: { name }}) RETURN p';
$query = new EverymanNeo4jCypherQuery(
$neo4jClient,
$queryString,
['name' => ‘Jeremy Kendall']
);
$result = $query->getResultSet();
Named Parameters
Named Parameters
$queryString =
'MATCH (p:Person { name: { name }}) RETURN p';
$query = new EverymanNeo4jCypherQuery(
$neo4jClient,
$queryString,
['name' => ‘Jeremy Kendall']
);
$result = $query->getResultSet();
Named Parameters
$queryString =
'MATCH (p:Person { name: { name }}) RETURN p';
$query = new EverymanNeo4jCypherQuery(
$neo4jClient,
$queryString,
['name' => ‘Jeremy Kendall']
);
$result = $query->getResultSet();
Content Modeling:
News Feeds
Graph Kit for PHP
https://github.com/GraphStory/graph-kit-php
News Feed
• Modeled as a list of posts
• Newest post first
• All subsequent posts follow
• Relationships: LASTPOST and NEXTPOST
LASTPOST
NEXTPOST
The Content Model
class Content
{
public $node;
public $nodeId;
public $contentId;
public $title;
public $url;
public $tagstr;
public $timestamp;
public $userNameForPost;
public $owner = false;
}
Adding Content
public static function add($username, Content $content)
{
$queryString =<<<CYPHER
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
CYPHER;
$query = new Query(
Neo4jClient::client(),
$queryString,
array(
'u' => $username,
'title' => $content->title,
'url' => $content->url,
'tagstr' => $content->tagstr,
'timestamp' => time(),
'contentId' => uniqid()
)
);
$result = $query->getResultSet();
return self::returnMappedContent($result);
}
Adding Content
public static function add($username, Content $content)
{
$queryString =<<<CYPHER
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
CYPHER;
$query = new Query(
Neo4jClient::client(),
$queryString,
array(
'u' => $username,
'title' => $content->title,
'url' => $content->url,
'tagstr' => $content->tagstr,
'timestamp' => time(),
'contentId' => uniqid()
)
);
$result = $query->getResultSet();
return self::returnMappedContent($result);
}
Adding Content
public static function add($username, Content $content)
{
$queryString =<<<CYPHER
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
CYPHER;
$query = new Query(
Neo4jClient::client(),
$queryString,
array(
'u' => $username,
'title' => $content->title,
'url' => $content->url,
'tagstr' => $content->tagstr,
'timestamp' => time(),
'contentId' => uniqid()
)
);
$result = $query->getResultSet();
return self::returnMappedContent($result);
}
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
MATCH (user { username: {u}})
OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost)
DELETE r
CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:
{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId:
{contentId} })
WITH p, collect(lastpost) as lastposts
FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x)
RETURN p, {u} as username, true as owner
Adding Content
$query = new Query(
$neo4jClient,
$queryString,
array(
'u' => $username,
'title' => $content->title,
'url' => $content->url,
'tagstr' => $content->tagstr,
'timestamp' => time(),
'contentId' => uniqid()
)
);
$result = $query->getResultSet();
Retrieving Content
public static function getContent($username, $skip)
{
$queryString = <<<CYPHER
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
CYPHER;
$query = new Query(
Neo4jClient::client(),
$queryString,
array(
'u' => $username,
'skip' => $skip,
)
);
$result = $query->getResultSet();
return self::returnMappedContent($result);
}
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Retrieving Content
MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f
WITH DISTINCT f, u
MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p
RETURN p, f.username as username, f = u as owner
ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
Editing Content
public static function edit(Content $content)
{
$updatedAt = time();
$node = $content->node;
$node->setProperty('title', $content->title);
$node->setProperty('url', $content->url);
$node->setProperty('tagstr', $content->tagstr);
$node->setProperty('updated', $updatedAt);
$node->save();
$content->updated = $updatedAt;
return $content;
}
Editing Content
public static function edit(Content $content)
{
$updatedAt = time();
$node = $content->node;
$node->setProperty('title', $content->title);
$node->setProperty('url', $content->url);
$node->setProperty('tagstr', $content->tagstr);
$node->setProperty('updated', $updatedAt);
$node->save();
$content->updated = $updatedAt;
return $content;
}
Editing Content
public static function edit(Content $content)
{
$updatedAt = time();
$node = $content->node;
$node->setProperty('title', $content->title);
$node->setProperty('url', $content->url);
$node->setProperty('tagstr', $content->tagstr);
$node->setProperty('updated', $updatedAt);
$node->save();
$content->updated = $updatedAt;
return $content;
}
Editing Content
public static function edit(Content $content)
{
$updatedAt = time();
$node = $content->node;
$node->setProperty('title', $content->title);
$node->setProperty('url', $content->url);
$node->setProperty('tagstr', $content->tagstr);
$node->setProperty('updated', $updatedAt);
$node->save();
$content->updated = $updatedAt;
return $content;
}
Editing Content
public static function edit(Content $content)
{
$updatedAt = time();
$node = $content->node;
$node->setProperty('title', $content->title);
$node->setProperty('url', $content->url);
$node->setProperty('tagstr', $content->tagstr);
$node->setProperty('updated', $updatedAt);
$node->save();
$content->updated = $updatedAt;
return $content;
}
Deleting Content
public static function delete($username, $contentId)
{
$queryString = self::getDeleteQueryString(
$username,
$contentId
);
$params = array(
'username' => $username,
'contentId' => $contentId,
);
$query = new Query(
$neo4jClient,
$queryString,
$params
);
$query->getResultSet();
}
Deleting Content
public static function delete($username, $contentId)
{
$queryString = self::getDeleteQueryString(
$username,
$contentId
);
$params = array(
'username' => $username,
'contentId' => $contentId,
);
$query = new Query(
$neo4jClient,
$queryString,
$params
);
$query->getResultSet();
}
Deleting Content
public static function delete($username, $contentId)
{
$queryString = self::getDeleteQueryString(
$username,
$contentId
);
$params = array(
'username' => $username,
'contentId' => $contentId,
);
$query = new Query(
$neo4jClient,
$queryString,
$params
);
$query->getResultSet();
}
Deleting Content
public static function delete($username, $contentId)
{
$queryString = self::getDeleteQueryString(
$username,
$contentId
);
$params = array(
'username' => $username,
'contentId' => $contentId,
);
$query = new Query(
$neo4jClient,
$queryString,
$params
);
$query->getResultSet();
}
Deleting Content: Leaf
// If leaf
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(c:Content { contentId: { contentId }})
WITH c
MATCH (c)-[r]-()
DELETE c, r
Deleting Content: Leaf
// If leaf
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(c:Content { contentId: { contentId }})
WITH c
MATCH (c)-[r]-()
DELETE c, r
Deleting Content: Leaf
// If leaf
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(c:Content { contentId: { contentId }})
WITH c
MATCH (c)-[r]-()
DELETE c, r
Deleting Content: Leaf
// If leaf
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(c:Content { contentId: { contentId }})
WITH c
MATCH (c)-[r]-()
DELETE c, r
Deleting Content: Leaf
// If leaf
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(c:Content { contentId: { contentId }})
WITH c
MATCH (c)-[r]-()
DELETE c, r
Deleting Content: LASTPOST
// If last
MATCH (u:User { username: { username }})-[lp:LASTPOST]-
>(del:Content { contentId: { contentId }})-[np:NEXTPOST]-
>(nextPost)
CREATE UNIQUE (u)-[:LASTPOST]->(nextPost)
DELETE lp, del, np
Deleting Content: LASTPOST
// If last
MATCH (u:User { username: { username }})-[lp:LASTPOST]-
>(del:Content { contentId: { contentId }})-[np:NEXTPOST]-
>(nextPost)
CREATE UNIQUE (u)-[:LASTPOST]->(nextPost)
DELETE lp, del, np
Deleting Content: LASTPOST
// If last
MATCH (u:User { username: { username }})-[lp:LASTPOST]-
>(del:Content { contentId: { contentId }})-[np:NEXTPOST]-
>(nextPost)
CREATE UNIQUE (u)-[:LASTPOST]->(nextPost)
DELETE lp, del, np
Deleting Content: LASTPOST
// If last
MATCH (u:User { username: { username }})-[lp:LASTPOST]-
>(del:Content { contentId: { contentId }})-[np:NEXTPOST]-
>(nextPost)
CREATE UNIQUE (u)-[:LASTPOST]->(nextPost)
DELETE lp, del, np
Deleting Content: Other
// All other
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(before),
(before)-[delBefore]->(del:Content { contentId:
{ contentId }})-[delAfter]->(after)
CREATE UNIQUE (before)-[:NEXTPOST]->(after)
DELETE del, delBefore, delAfter
Deleting Content: Other
// All other
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(before),
(before)-[delBefore]->(del:Content { contentId:
{ contentId }})-[delAfter]->(after)
CREATE UNIQUE (before)-[:NEXTPOST]->(after)
DELETE del, delBefore, delAfter
Deleting Content: Other
// All other
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(before),
(before)-[delBefore]->(del:Content { contentId:
{ contentId }})-[delAfter]->(after)
CREATE UNIQUE (before)-[:NEXTPOST]->(after)
DELETE del, delBefore, delAfter
Deleting Content: Other
// All other
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(before),
(before)-[delBefore]->(del:Content { contentId:
{ contentId }})-[delAfter]->(after)
CREATE UNIQUE (before)-[:NEXTPOST]->(after)
DELETE del, delBefore, delAfter
Deleting Content: Other
// All other
MATCH (u:User { username: { username }})-[:LASTPOST|
NEXTPOST*0..]->(before),
(before)-[delBefore]->(del:Content { contentId:
{ contentId }})-[delAfter]->(after)
CREATE UNIQUE (before)-[:NEXTPOST]->(after)
DELETE del, delBefore, delAfter
Questions?
Thanks!
jeremy.kendall@graphstory.com
@JeremyKendall
http://www.graphstory.com

More Related Content

What's hot

(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and ProfitOlaf Alders
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway ichikaway
 
Terms of endearment - the ElasticSearch Query DSL explained
Terms of endearment - the ElasticSearch Query DSL explainedTerms of endearment - the ElasticSearch Query DSL explained
Terms of endearment - the ElasticSearch Query DSL explainedclintongormley
 
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK - Nicola Iarocci - Co...
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK -  Nicola Iarocci - Co...RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK -  Nicola Iarocci - Co...
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK - Nicola Iarocci - Co...Codemotion
 
PHP Tutorial (funtion)
PHP Tutorial (funtion)PHP Tutorial (funtion)
PHP Tutorial (funtion)Tinnakorn Puttha
 
Current state-of-php
Current state-of-phpCurrent state-of-php
Current state-of-phpRichard McIntyre
 
Fazendo mĂĄgica com ElasticSearch
Fazendo mĂĄgica com ElasticSearchFazendo mĂĄgica com ElasticSearch
Fazendo mĂĄgica com ElasticSearchPedro Franceschi
 
How to use MongoDB with CakePHP
How to use MongoDB with CakePHPHow to use MongoDB with CakePHP
How to use MongoDB with CakePHPichikaway
 
jQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20PresentationjQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20Presentationguestcf600a
 
10gen Presents Schema Design and Data Modeling
10gen Presents Schema Design and Data Modeling10gen Presents Schema Design and Data Modeling
10gen Presents Schema Design and Data ModelingDATAVERSITY
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018Adam Tomat
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationDaniel Yuschick
 
SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015Mark Baker
 
How else can you write the code in PHP?
How else can you write the code in PHP?How else can you write the code in PHP?
How else can you write the code in PHP?Maksym Hopei
 

What's hot (16)

(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
 
Terms of endearment - the ElasticSearch Query DSL explained
Terms of endearment - the ElasticSearch Query DSL explainedTerms of endearment - the ElasticSearch Query DSL explained
Terms of endearment - the ElasticSearch Query DSL explained
 
Fantom and Tales
Fantom and TalesFantom and Tales
Fantom and Tales
 
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK - Nicola Iarocci - Co...
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK -  Nicola Iarocci - Co...RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK -  Nicola Iarocci - Co...
RESTFUL SERVICES MADE EASY: THE EVE REST API FRAMEWORK - Nicola Iarocci - Co...
 
PHP Tutorial (funtion)
PHP Tutorial (funtion)PHP Tutorial (funtion)
PHP Tutorial (funtion)
 
Current state-of-php
Current state-of-phpCurrent state-of-php
Current state-of-php
 
Fazendo mĂĄgica com ElasticSearch
Fazendo mĂĄgica com ElasticSearchFazendo mĂĄgica com ElasticSearch
Fazendo mĂĄgica com ElasticSearch
 
How to use MongoDB with CakePHP
How to use MongoDB with CakePHPHow to use MongoDB with CakePHP
How to use MongoDB with CakePHP
 
jQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20PresentationjQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20Presentation
 
10gen Presents Schema Design and Data Modeling
10gen Presents Schema Design and Data Modeling10gen Presents Schema Design and Data Modeling
10gen Presents Schema Design and Data Modeling
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass Presentation
 
My First Ruby
My First RubyMy First Ruby
My First Ruby
 
SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015
 
How else can you write the code in PHP?
How else can you write the code in PHP?How else can you write the code in PHP?
How else can you write the code in PHP?
 

Viewers also liked

Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tourBrad Montgomery
 
PHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodPHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodJeremy Kendall
 
Tdd in php a brief example
Tdd in php   a brief exampleTdd in php   a brief example
Tdd in php a brief exampleJeremy Kendall
 
Slim RedBeanPHP and Knockout
Slim RedBeanPHP and KnockoutSlim RedBeanPHP and Knockout
Slim RedBeanPHP and KnockoutVic Metcalfe
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLIDVic Metcalfe
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 
TDC SP 2015 - PHP7: melhor e mais rĂĄpido
TDC SP 2015 - PHP7: melhor e mais rĂĄpidoTDC SP 2015 - PHP7: melhor e mais rĂĄpido
TDC SP 2015 - PHP7: melhor e mais rĂĄpidoBruno Ricardo Siqueira
 

Viewers also liked (8)

Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tour
 
PHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodPHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the Good
 
Tdd in php a brief example
Tdd in php   a brief exampleTdd in php   a brief example
Tdd in php a brief example
 
Slim RedBeanPHP and Knockout
Slim RedBeanPHP and KnockoutSlim RedBeanPHP and Knockout
Slim RedBeanPHP and Knockout
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Php 101: PDO
Php 101: PDOPhp 101: PDO
Php 101: PDO
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
TDC SP 2015 - PHP7: melhor e mais rĂĄpido
TDC SP 2015 - PHP7: melhor e mais rĂĄpidoTDC SP 2015 - PHP7: melhor e mais rĂĄpido
TDC SP 2015 - PHP7: melhor e mais rĂĄpido
 

Similar to Leveraging the Power of Graph Databases in PHP

Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
 
DBIx::Skinnyと仲間たち
DBIx::Skinnyと仲間たちDBIx::Skinnyと仲間たち
DBIx::Skinnyと仲間たちRyo Miyake
 
Hands On Spring Data
Hands On Spring DataHands On Spring Data
Hands On Spring DataEric Bottard
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInautsWynn Netherland
 
Building Go Web Apps
Building Go Web AppsBuilding Go Web Apps
Building Go Web AppsMark
 
Zendcon 2007 Api Design
Zendcon 2007 Api DesignZendcon 2007 Api Design
Zendcon 2007 Api Designunodelostrece
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourPeter Friese
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Eve - REST API for Humans™
Eve - REST API for Humans™Eve - REST API for Humans™
Eve - REST API for Humans™Nicola Iarocci
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)Doris Chen
 
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Codemotion
 
Express Presentation
Express PresentationExpress Presentation
Express Presentationaaronheckmann
 
PostgreSQL Open SV 2018
PostgreSQL Open SV 2018PostgreSQL Open SV 2018
PostgreSQL Open SV 2018artgillespie
 
Schema Design with MongoDB
Schema Design with MongoDBSchema Design with MongoDB
Schema Design with MongoDBrogerbodamer
 
Routing @ Scuk.cz
Routing @ Scuk.czRouting @ Scuk.cz
Routing @ Scuk.czJakub Kulhan
 

Similar to Leveraging the Power of Graph Databases in PHP (20)

Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
 
DBIx::Skinnyと仲間たち
DBIx::Skinnyと仲間たちDBIx::Skinnyと仲間たち
DBIx::Skinnyと仲間たち
 
Hands On Spring Data
Hands On Spring DataHands On Spring Data
Hands On Spring Data
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
PHP API
PHP APIPHP API
PHP API
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInauts
 
Building Go Web Apps
Building Go Web AppsBuilding Go Web Apps
Building Go Web Apps
 
pyscript_django.pdf
pyscript_django.pdfpyscript_django.pdf
pyscript_django.pdf
 
Zendcon 2007 Api Design
Zendcon 2007 Api DesignZendcon 2007 Api Design
Zendcon 2007 Api Design
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
 
Django
DjangoDjango
Django
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Eve - REST API for Humans™
Eve - REST API for Humans™Eve - REST API for Humans™
Eve - REST API for Humans™
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
 
Express Presentation
Express PresentationExpress Presentation
Express Presentation
 
Jersey
JerseyJersey
Jersey
 
PostgreSQL Open SV 2018
PostgreSQL Open SV 2018PostgreSQL Open SV 2018
PostgreSQL Open SV 2018
 
Schema Design with MongoDB
Schema Design with MongoDBSchema Design with MongoDB
Schema Design with MongoDB
 
Routing @ Scuk.cz
Routing @ Scuk.czRouting @ Scuk.cz
Routing @ Scuk.cz
 

More from Jeremy Kendall

5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) CodeJeremy Kendall
 
Game Changing Dependency Management
Game Changing Dependency ManagementGame Changing Dependency Management
Game Changing Dependency ManagementJeremy Kendall
 
Keeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro frameworkKeeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro frameworkJeremy Kendall
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkJeremy Kendall
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy Kendall
 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05Jeremy Kendall
 
TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25Jeremy Kendall
 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormJeremy Kendall
 
Zero to ZF in 10 Minutes
Zero to ZF in 10 MinutesZero to ZF in 10 Minutes
Zero to ZF in 10 MinutesJeremy Kendall
 
A Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormA Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormJeremy Kendall
 
Zero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesZero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesJeremy Kendall
 

More from Jeremy Kendall (11)

5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code
 
Game Changing Dependency Management
Game Changing Dependency ManagementGame Changing Dependency Management
Game Changing Dependency Management
 
Keeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro frameworkKeeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro framework
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05
 
TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25
 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
 
Zero to ZF in 10 Minutes
Zero to ZF in 10 MinutesZero to ZF in 10 Minutes
Zero to ZF in 10 Minutes
 
A Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormA Brief Introduction to Zend_Form
A Brief Introduction to Zend_Form
 
Zero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesZero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutes
 

Recently uploaded

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 

Recently uploaded (20)

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 

Leveraging the Power of Graph Databases in PHP

  • 1. Leveraging the Power of Graph Databases in PHP Jeremy Kendall Atlanta PHP April 2015
  • 3. Also - New Father
  • 7. Graph Databases • Data Model • Nodes with properties • Typed relationships • Strengths • Highly connected data • ACID • Weaknesses • Paradigm shift • Examples • Neo4j, Titan, OrientDB
  • 8. Why Care? • All the NoSQL Joy • Schema-less • Semi-structured data • Escape from JOIN Hell • Speed
  • 9. Why Care? • Relationships have 1st class status • Just as important as the objects they connect • You can have properties & labels • Multiple relationships
  • 11. Speed Depth MySQL Query Time Neo4j Query Time Records Returned 2 0.028 (28 MS) 0.04 ~900 3 0.213 0.06 ~999 4 10.273 0.07 ~999 5 92.613 0.07 ~999 1,000 people with an average 50 friends each
  • 12. Crazy Speed Depth MySQL Query Time Neo4j Query Time Records Returned 2 0.016 (16 MS) 0.01 ~2500 3 30.27 0.168 ~125,000 4 1543.505 1.359 ~600,000 5 Stopped after 1 hour 2.132 ~800,000 1,000,000 people with an average 50 friends each
  • 13.
  • 15. Cypher • Neo4j’s declarative query language • Easy to pick up • Some clauses and concepts familiar from SQL
  • 17. Goal
  • 18. Create Some Nodes CREATE (jk:Person { name: "Jeremy Kendall" }) CREATE (gs:Company { name: "Graph Story" }) CREATE (tn:State { name: "Tennessee" }) CREATE (memphis:City { name: "Memphis" }) CREATE (nashville:City { name: "Nashville" }) CREATE (hotchicken:Food { name: "Hot Chicken" }) CREATE (bbq:Food { name: "Barbecue" }) CREATE (photography:Hobby { name: "Photography" }) CREATE (language:Language { name: "PHP" }) // . . . snip . . .
  • 19. Create Some Relationships // . . . snip . . . CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs), (jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville), (hotchicken)-[:ONLY_IN]->(nashville), (bbq)-[:ONLY_IN]->(memphis), (jk)-[:LOVES]->(hotchicken), // . . . snip . . .
  • 20. Create Some Relationships // . . . snip . . . CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs), (jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville), (hotchicken)-[:ONLY_IN]->(nashville), (bbq)-[:ONLY_IN]->(memphis), (jk)-[:LOVES]->(hotchicken), // . . . snip . . .
  • 21. Create Some Relationships // . . . snip . . . CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs), (jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville), (hotchicken)-[:ONLY_IN]->(nashville), (bbq)-[:ONLY_IN]->(memphis), (jk)-[:LOVES]->(hotchicken), // . . . snip . . .
  • 22. Create Some Relationships // . . . snip . . . CREATE (jk)-[:WORKS_AT { title: {"CTO"}]->(gs), (jk)-[:LIVES_IN]->(memphis)-[:LIVED_IN]->(nashville), (hotchicken)-[:ONLY_IN]->(nashville), (bbq)-[:ONLY_IN]->(memphis), (jk)-[:LOVES]->(hotchicken), // . . . snip . . .
  • 23. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 24. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 25. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 26. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 27. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 28. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 29. Example Cypher Query MATCH (p:Person { name: "Jeremy Kendall" })-[:LOVES]->(l) WITH p, l MATCH (p)-[:WORKS_AT]->(j) WITH p, l, j MATCH (p)-[:LIVES_IN]->(c:City)-[:LIVED_IN*0..]->(o:City) RETURN p, l, j, o
  • 36. Neo4jPHP • PHP wrapper for the Neo4j REST API • Installable via Composer • Used internally at Graph Story • Used in this presentation • Well tested • https://packagist.org/packages/everyman/ neo4jphp
  • 37. Also see: NeoClient • Written by Neoxygen • Alternative PHP wrapper for the Neo4j REST API • Installable via Composer • Accepted for internal use at Graph Story • Well tested • https://packagist.org/packages/neoxygen/neoclient
  • 38. Connecting $neo4jClient = new EverymanNeo4jClient( ‘yourgraph.example.com’, 7473 ); $neo4jClient->getTransport() ->setAuth('username', 'password') ->getTransport()->useHttps();
  • 39. Creating a Node and Label $node = new Node($neo4jClient); $label = $neo4jClient->makeLabel('Person'); $node->setProperty('name', ‘Jeremy Kendall'); $node->save()->addLabels(array($label));
  • 40. Searching // Searching for a label by property $label = $neo4jClient->makeLabel('Person'); $nodes = $label->getNodes('name', $name);
  • 41. Querying (Cypher) $queryString = 'MATCH (p:Person { name: { name }}) RETURN p'; $query = new EverymanNeo4jCypherQuery( $neo4jClient, $queryString, ['name' => ‘Jeremy Kendall'] ); $result = $query->getResultSet();
  • 43. Named Parameters $queryString = 'MATCH (p:Person { name: { name }}) RETURN p'; $query = new EverymanNeo4jCypherQuery( $neo4jClient, $queryString, ['name' => ‘Jeremy Kendall'] ); $result = $query->getResultSet();
  • 44. Named Parameters $queryString = 'MATCH (p:Person { name: { name }}) RETURN p'; $query = new EverymanNeo4jCypherQuery( $neo4jClient, $queryString, ['name' => ‘Jeremy Kendall'] ); $result = $query->getResultSet();
  • 45. Content Modeling: News Feeds Graph Kit for PHP https://github.com/GraphStory/graph-kit-php
  • 46. News Feed • Modeled as a list of posts • Newest post rst • All subsequent posts follow • Relationships: LASTPOST and NEXTPOST
  • 49. The Content Model class Content { public $node; public $nodeId; public $contentId; public $title; public $url; public $tagstr; public $timestamp; public $userNameForPost; public $owner = false; }
  • 50. Adding Content public static function add($username, Content $content) { $queryString =<<<CYPHER MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner CYPHER; $query = new Query( Neo4jClient::client(), $queryString, array( 'u' => $username, 'title' => $content->title, 'url' => $content->url, 'tagstr' => $content->tagstr, 'timestamp' => time(), 'contentId' => uniqid() ) ); $result = $query->getResultSet(); return self::returnMappedContent($result); }
  • 51. Adding Content public static function add($username, Content $content) { $queryString =<<<CYPHER MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner CYPHER; $query = new Query( Neo4jClient::client(), $queryString, array( 'u' => $username, 'title' => $content->title, 'url' => $content->url, 'tagstr' => $content->tagstr, 'timestamp' => time(), 'contentId' => uniqid() ) ); $result = $query->getResultSet(); return self::returnMappedContent($result); }
  • 52. Adding Content public static function add($username, Content $content) { $queryString =<<<CYPHER MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url:{url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner CYPHER; $query = new Query( Neo4jClient::client(), $queryString, array( 'u' => $username, 'title' => $content->title, 'url' => $content->url, 'tagstr' => $content->tagstr, 'timestamp' => time(), 'contentId' => uniqid() ) ); $result = $query->getResultSet(); return self::returnMappedContent($result); }
  • 53. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 54. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 55. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 56. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 57. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 58. Adding Content MATCH (user { username: {u}}) OPTIONAL MATCH (user)-[r:LASTPOST]->(lastpost) DELETE r CREATE (user)-[:LASTPOST]->(p:Content { title:{title}, url: {url}, tagstr:{tagstr}, timestamp:{timestamp}, contentId: {contentId} }) WITH p, collect(lastpost) as lastposts FOREACH (x IN lastposts | CREATE p-[:NEXTPOST]->x) RETURN p, {u} as username, true as owner
  • 59. Adding Content $query = new Query( $neo4jClient, $queryString, array( 'u' => $username, 'title' => $content->title, 'url' => $content->url, 'tagstr' => $content->tagstr, 'timestamp' => time(), 'contentId' => uniqid() ) ); $result = $query->getResultSet();
  • 60. Retrieving Content public static function getContent($username, $skip) { $queryString = <<<CYPHER MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4 CYPHER; $query = new Query( Neo4jClient::client(), $queryString, array( 'u' => $username, 'skip' => $skip, ) ); $result = $query->getResultSet(); return self::returnMappedContent($result); }
  • 61. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 62. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 63. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 64. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 65. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 66. Retrieving Content MATCH (u:User { username: { u }})-[:FOLLOWS*0..1]->f WITH DISTINCT f, u MATCH f-[:LASTPOST]-lp-[:NEXTPOST*0..]-p RETURN p, f.username as username, f = u as owner ORDER BY p.timestamp desc SKIP { skip } LIMIT 4
  • 67. Editing Content public static function edit(Content $content) { $updatedAt = time(); $node = $content->node; $node->setProperty('title', $content->title); $node->setProperty('url', $content->url); $node->setProperty('tagstr', $content->tagstr); $node->setProperty('updated', $updatedAt); $node->save(); $content->updated = $updatedAt; return $content; }
  • 68. Editing Content public static function edit(Content $content) { $updatedAt = time(); $node = $content->node; $node->setProperty('title', $content->title); $node->setProperty('url', $content->url); $node->setProperty('tagstr', $content->tagstr); $node->setProperty('updated', $updatedAt); $node->save(); $content->updated = $updatedAt; return $content; }
  • 69. Editing Content public static function edit(Content $content) { $updatedAt = time(); $node = $content->node; $node->setProperty('title', $content->title); $node->setProperty('url', $content->url); $node->setProperty('tagstr', $content->tagstr); $node->setProperty('updated', $updatedAt); $node->save(); $content->updated = $updatedAt; return $content; }
  • 70. Editing Content public static function edit(Content $content) { $updatedAt = time(); $node = $content->node; $node->setProperty('title', $content->title); $node->setProperty('url', $content->url); $node->setProperty('tagstr', $content->tagstr); $node->setProperty('updated', $updatedAt); $node->save(); $content->updated = $updatedAt; return $content; }
  • 71. Editing Content public static function edit(Content $content) { $updatedAt = time(); $node = $content->node; $node->setProperty('title', $content->title); $node->setProperty('url', $content->url); $node->setProperty('tagstr', $content->tagstr); $node->setProperty('updated', $updatedAt); $node->save(); $content->updated = $updatedAt; return $content; }
  • 72. Deleting Content public static function delete($username, $contentId) { $queryString = self::getDeleteQueryString( $username, $contentId ); $params = array( 'username' => $username, 'contentId' => $contentId, ); $query = new Query( $neo4jClient, $queryString, $params ); $query->getResultSet(); }
  • 73. Deleting Content public static function delete($username, $contentId) { $queryString = self::getDeleteQueryString( $username, $contentId ); $params = array( 'username' => $username, 'contentId' => $contentId, ); $query = new Query( $neo4jClient, $queryString, $params ); $query->getResultSet(); }
  • 74. Deleting Content public static function delete($username, $contentId) { $queryString = self::getDeleteQueryString( $username, $contentId ); $params = array( 'username' => $username, 'contentId' => $contentId, ); $query = new Query( $neo4jClient, $queryString, $params ); $query->getResultSet(); }
  • 75. Deleting Content public static function delete($username, $contentId) { $queryString = self::getDeleteQueryString( $username, $contentId ); $params = array( 'username' => $username, 'contentId' => $contentId, ); $query = new Query( $neo4jClient, $queryString, $params ); $query->getResultSet(); }
  • 76. Deleting Content: Leaf // If leaf MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(c:Content { contentId: { contentId }}) WITH c MATCH (c)-[r]-() DELETE c, r
  • 77. Deleting Content: Leaf // If leaf MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(c:Content { contentId: { contentId }}) WITH c MATCH (c)-[r]-() DELETE c, r
  • 78. Deleting Content: Leaf // If leaf MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(c:Content { contentId: { contentId }}) WITH c MATCH (c)-[r]-() DELETE c, r
  • 79. Deleting Content: Leaf // If leaf MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(c:Content { contentId: { contentId }}) WITH c MATCH (c)-[r]-() DELETE c, r
  • 80. Deleting Content: Leaf // If leaf MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(c:Content { contentId: { contentId }}) WITH c MATCH (c)-[r]-() DELETE c, r
  • 81. Deleting Content: LASTPOST // If last MATCH (u:User { username: { username }})-[lp:LASTPOST]- >(del:Content { contentId: { contentId }})-[np:NEXTPOST]- >(nextPost) CREATE UNIQUE (u)-[:LASTPOST]->(nextPost) DELETE lp, del, np
  • 82. Deleting Content: LASTPOST // If last MATCH (u:User { username: { username }})-[lp:LASTPOST]- >(del:Content { contentId: { contentId }})-[np:NEXTPOST]- >(nextPost) CREATE UNIQUE (u)-[:LASTPOST]->(nextPost) DELETE lp, del, np
  • 83. Deleting Content: LASTPOST // If last MATCH (u:User { username: { username }})-[lp:LASTPOST]- >(del:Content { contentId: { contentId }})-[np:NEXTPOST]- >(nextPost) CREATE UNIQUE (u)-[:LASTPOST]->(nextPost) DELETE lp, del, np
  • 84. Deleting Content: LASTPOST // If last MATCH (u:User { username: { username }})-[lp:LASTPOST]- >(del:Content { contentId: { contentId }})-[np:NEXTPOST]- >(nextPost) CREATE UNIQUE (u)-[:LASTPOST]->(nextPost) DELETE lp, del, np
  • 85. Deleting Content: Other // All other MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(before), (before)-[delBefore]->(del:Content { contentId: { contentId }})-[delAfter]->(after) CREATE UNIQUE (before)-[:NEXTPOST]->(after) DELETE del, delBefore, delAfter
  • 86. Deleting Content: Other // All other MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(before), (before)-[delBefore]->(del:Content { contentId: { contentId }})-[delAfter]->(after) CREATE UNIQUE (before)-[:NEXTPOST]->(after) DELETE del, delBefore, delAfter
  • 87. Deleting Content: Other // All other MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(before), (before)-[delBefore]->(del:Content { contentId: { contentId }})-[delAfter]->(after) CREATE UNIQUE (before)-[:NEXTPOST]->(after) DELETE del, delBefore, delAfter
  • 88. Deleting Content: Other // All other MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(before), (before)-[delBefore]->(del:Content { contentId: { contentId }})-[delAfter]->(after) CREATE UNIQUE (before)-[:NEXTPOST]->(after) DELETE del, delBefore, delAfter
  • 89. Deleting Content: Other // All other MATCH (u:User { username: { username }})-[:LASTPOST| NEXTPOST*0..]->(before), (before)-[delBefore]->(del:Content { contentId: { contentId }})-[delAfter]->(after) CREATE UNIQUE (before)-[:NEXTPOST]->(after) DELETE del, delBefore, delAfter