Introducing Topic Maps Patrick Durusau Convener, Topic Maps Working Group, ISO.
Graph Modeling Do's and Don'ts - Patrick Durusau, patrick
Transcript of Graph Modeling Do's and Don'ts - Patrick Durusau, patrick
![Page 2: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/2.jpg)
#neo4j
Credit for the slides goes to Ian Robinson @iansrobinson on twitter
![Page 3: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/3.jpg)
#neo4j
Outline
• Property Graph Refresher
• A modeling workflow
• Modeling tips
• Testing your data model
![Page 4: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/4.jpg)
#neo4j
Property Graph Refresher
![Page 5: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/5.jpg)
#neo4j
Property Graph Data Model
![Page 6: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/6.jpg)
#neo4j
Four Building Blocks
• Nodes
• Relationships
• Properties
• Labels
![Page 7: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/7.jpg)
#neo4j
Nodes
![Page 8: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/8.jpg)
#neo4j
Nodes
• Used to represent entities and complex value types in your domain
• Can contain properties – Used to represent entity attributes and/or
metadata (e.g. timestamps, version)
– Key-value pairs • Java primitives
• Arrays
• null is not a valid value
– Every node can have different properties
![Page 9: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/9.jpg)
#neo4j
Entities and Value Types
• Entities – Have unique conceptual identity
– Change attribute values, but identity remains the same
• Value types – No conceptual identity
– Can substitute for each other if they have the same value • Simple: single value (e.g. colour, category)
• Complex: multiple attributes (e.g. address)
![Page 10: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/10.jpg)
#neo4j
Relationships
![Page 11: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/11.jpg)
#neo4j
Relationships
• Every relationship has a name and a direction – Add structure to the graph
– Provide semantic context for nodes
• Can contain properties – Used to represent quality or weight of
relationship, or metadata
• Every relationship must have a start node and end node – No dangling relationships
![Page 12: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/12.jpg)
#neo4j
Relationships (continued)
Nodes can have more than one relationship
Self relationships are allowed
Nodes can be connected by more than one relationship
![Page 13: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/13.jpg)
#neo4j
Variable Structure
• Relationships are defined with regard to node instances, not classes of nodes
– Two nodes representing the same kind of “thing” can be connected in very different ways
• Allows for structural variation in the domain
– Contrast with relational schemas, where foreign key relationships apply to all rows in a table
• No need to use null to represent the absence of a connection
![Page 14: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/14.jpg)
#neo4j
Labels
![Page 15: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/15.jpg)
#neo4j
Labels
• Every node can have zero or more labels
• Used to represent roles (e.g. user, product, company)
– Group nodes
– Allow us to associate indexes and constraints with groups of nodes
![Page 16: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/16.jpg)
#neo4j
Four Building Blocks
• Nodes – Entities
• Relationships – Connect entities and structure domain
• Properties – Entity attributes, relationship qualities, and
metadata
• Labels – Group nodes by role
![Page 17: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/17.jpg)
#neo4j
A modeling workflow
![Page 18: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/18.jpg)
#neo4j
Models
Images: en.wikipedia.org
![Page 19: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/19.jpg)
#neo4j
Design for Queryability
Model Query
![Page 20: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/20.jpg)
#neo4j
User stories
![Page 21: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/21.jpg)
#neo4j
Derive questions
Which people, who work for the same company as me, have similar skills to me?
![Page 22: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/22.jpg)
#neo4j
Identify entities
Which people, who work for the same company as me, have similar skills to me?
person
company
skill
![Page 23: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/23.jpg)
#neo4j
Identify relationships between entities
Which people, who work for the same company as me, have similar skills to me?
person WORKS_FOR company
person HAS_SKILL skill
![Page 24: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/24.jpg)
#neo4j
Convert to Cypher paths
person WORKS_FOR company
person HAS_SKILL skill
(person)-[:WORKS_FOR]->(company),
(person)-[:HAS_SKILL]->(skill)
![Page 25: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/25.jpg)
#neo4j
Cypher paths
(person)-[:WORKS_FOR]->(company),
(person)-[:HAS_SKILL]->(skill)
(company)<-[:WORKS_FOR]-(person)-[:HAS_SKILL]->(skill)
![Page 26: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/26.jpg)
#neo4j
Data model
(company)<-[:WORKS_FOR]-(person)-[:HAS_SKILL]->(skill)
![Page 27: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/27.jpg)
#neo4j
Formulating question as graph pattern
Which people, who work for the same company as me, have similar skills to me?
![Page 28: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/28.jpg)
#neo4j
Cypher query
Which people, who work for the same company as me, have similar skills to me?
MATCH (company)<-[:WORKS_FOR]-(me:person)-[:HAS_SKILL]->(skill),
(company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill)
WHERE me.name = {name}
RETURN colleague.name AS name,
count(skill) AS score,
collect(skill.name) AS skills
ORDER BY score DESC
![Page 29: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/29.jpg)
#neo4j
Graph pattern
Which people, who work for the same company as me, have similar skills to me?
MATCH (company)<-[:WORKS_FOR]-(me:person)-[:HAS_SKILL]->(skill),
(company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill)
WHERE me.name = {name}
RETURN colleague.name AS name,
count(skill) AS score,
collect(skill.name) AS skills
ORDER BY score DESC
![Page 30: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/30.jpg)
#neo4j
Anchor pattern in graph
Which people, who work for the same company as me, have similar skills to me?
MATCH (company)<-[:WORKS_FOR]-(me:person)-[:HAS_SKILL]->(skill),
(company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill)
WHERE me.name = {name}
RETURN colleague.name AS name,
count(skill) AS score,
collect(skill.name) AS skills
ORDER BY score DESC
If an index for Person.name exists,
Cypher will use it
![Page 31: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/31.jpg)
#neo4j
Create projection of results
Which people, who work for the same company as me, have similar skills to me?
MATCH (company)<-[:WORKS_FOR]-(me:person)-[:HAS_SKILL]->(skill),
(company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill)
WHERE me.name = {name}
RETURN colleague.name AS name,
count(skill) AS score,
collect(skill.name) AS skills
ORDER BY score DESC
![Page 32: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/32.jpg)
#neo4j
First match
![Page 33: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/33.jpg)
#neo4j
Second match
![Page 34: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/34.jpg)
#neo4j
Third match
![Page 35: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/35.jpg)
#neo4j
Running the query
+-----------------------------------+
| name | score | skills |
+-----------------------------------+
| "Lucy" | 2 | ["Java","Neo4j"] |
| "Bill" | 1 | ["Neo4j"] |
+-----------------------------------+
2 rows
![Page 36: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/36.jpg)
#neo4j
From user story to model
MATCH (company)<-[:WORKS_FOR]-(me:person)-[:HAS_SKILL]->(skill),
(company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill)
WHERE me.name = {name}
RETURN colleague.name AS name,
count(skill) AS score,
collect(skill.name) AS skills
ORDER BY score DESC
(company)<-[:WORKS_FOR]-(person)-[:HAS_SKILL]->(skill)
person WORKS_FOR company
person HAS_SKILL skill
? Which people, who work for the same company as me, have similar skills to me?
![Page 37: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/37.jpg)
#neo4j
Modeling tips
![Page 38: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/38.jpg)
#neo4j
Nodes for things
![Page 39: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/39.jpg)
#neo4j
Labels for grouping
![Page 40: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/40.jpg)
#neo4j
Relationships for structure
![Page 41: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/41.jpg)
#neo4j
Properties vs Relationships
![Page 42: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/42.jpg)
#neo4j
Use relationships when… • You need to specify the weight, strength, or
some other quality of the relationship
• AND/OR the attribute value comprises a complex value type (e.g. address)
• Examples:
– Find all my colleagues who are expert (relationship quality) at a skill (attribute value) we have in common
– Find all recent orders delivered to the same delivery address (complex value type)
![Page 43: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/43.jpg)
#neo4j
Find Expert Colleagues
![Page 44: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/44.jpg)
#neo4j
Find Expert Colleagues MATCH (user:Person)-[:HAS_SKILL]->(skill),
(user)-[:WORKS_FOR]->(company),
(colleague)-[:WORKS_FOR]->(company),
(colleague)-[r:HAS_SKILL]->(skill)
WHERE user.name = {name} AND r.level = {skillLevel}
RETURN colleague.name AS name, skill.name AS skill
![Page 45: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/45.jpg)
#neo4j
Relate and Filter MATCH (user:Person)-[:HAS_SKILL]->(skill),
(user)-[:WORKS_FOR]->(company),
(colleague)-[:WORKS_FOR]->(company),
(colleague)-[r:HAS_SKILL]->(skill)
WHERE user.name = {name} AND r.level = {skillLevel}
RETURN colleague.name AS name, skill.name AS skill
![Page 46: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/46.jpg)
#neo4j
Use properties when… • There’s no need to qualify the relationship
• AND the attribute value comprises a simple value type (e.g. colour)
• Examples:
– Find those projects written by contributors to my projects that use the same language (attribute value) as my projects
![Page 47: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/47.jpg)
#neo4j
Find Projects With Same Languages
![Page 48: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/48.jpg)
#neo4j
Find Projects With Same Languages
MATCH (user:User)-[:WROTE]->(project:Project),
(contributor)-[:CONTRIBUTED_TO]->(project),
(contributor)-[:WROTE]->(otherProject:Project)
WHERE user.username = {username}
AND ANY (otherLanguage IN otherProject.language
WHERE ANY (language IN project.language
WHERE language = otherLanguage))
RETURN contributor.username AS username,
otherProject.name AS project,
otherProject.language AS languages
![Page 49: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/49.jpg)
#neo4j
Relate and Filter
MATCH (user:User)-[:WROTE]->(project:Project),
(contributor)-[:CONTRIBUTED_TO]->(project),
(contributor)-[:WROTE]->(otherProject:Project)
WHERE user.username = {username}
AND ANY (otherLanguage IN otherProject.language
WHERE ANY (language IN project.language
WHERE language = otherLanguage))
RETURN contributor.username AS username,
otherProject.name AS project,
otherProject.language AS languages
![Page 50: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/50.jpg)
#neo4j
If Performance is Critical…
• Small property lookup on a node will be quicker than traversing a relationship
– But traversing a relationship is still faster than a SQL join…
• However, many small properties on a node, or a lookup on a large string or large array property will impact performance
– Always performance test against a representative dataset
![Page 51: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/51.jpg)
#neo4j
Relationship Granularity
![Page 52: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/52.jpg)
#neo4j
General Relationships • Qualified by property
![Page 53: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/53.jpg)
#neo4j
Easy to Query Across All Types
MATCH (person)-[a:ADDRESS]->(address)
WHERE person.name = {name}
RETURN a.type AS type,
address.firstline AS firstline
![Page 54: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/54.jpg)
#neo4j
Property Access to Discover Sub-Types
MATCH (person)-[a:ADDRESS]->(address)
WHERE person.name = {name}
AND a.type = {type}
RETURN address.firstline AS firstline
![Page 55: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/55.jpg)
#neo4j
Specific Relationships
![Page 56: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/56.jpg)
#neo4j
Easy to Query Specific Types
MATCH (person)-[:HOME_ADDRESS]->(address)
WHERE person.name = {name}
RETURN address.firstline AS firstline
![Page 57: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/57.jpg)
#neo4j
Cumbersome to Discover All Types
MATCH (person)-
[a:HOME_ADDRESS|WORK_ADDRESS]
->(address)
WHERE person.name = {name}
RETURN type(a) AS type,
address.firstline AS firstline
![Page 58: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/58.jpg)
#neo4j
Cumbersome to Discover All Types
MATCH (person)-
[a:HOME_ADDRESS|WORK_ADDRESS]
->(address)
WHERE person.name = {name}
RETURN type(a) AS type,
address.firstline AS firstline
![Page 59: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/59.jpg)
#neo4j
Best of Both Worlds
![Page 60: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/60.jpg)
#neo4j
Don’t model entities as relationships
• Limits data model evolution
– Unable to associate more entities
• Entities sometimes hidden in a verb
• Smells:
– Lots of attribute-like properties
– Property value redundancy
– Heavy use of relationship indexes
![Page 61: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/61.jpg)
#neo4j
Example: Reviews
![Page 62: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/62.jpg)
#neo4j
Add another review
![Page 63: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/63.jpg)
#neo4j
And another
![Page 64: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/64.jpg)
#neo4j
Problems
• Redundant data (2 x amazon.co.uk)
• Difficult to find reviews for source
• Users can’t comment on reviews
![Page 65: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/65.jpg)
#neo4j
Revised model
![Page 66: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/66.jpg)
#neo4j
Model actions in terms of products
![Page 67: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/67.jpg)
#neo4j
Testing
![Page 68: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/68.jpg)
#neo4j
Test-driven data modeling
• Unit test with small, well-known datasets
– Inject small graphs to test individual queries
– Datasets express understanding of domain
– Use the tests to identify regressions as your data model evolves
• Performance test queries against representative dataset
![Page 69: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/69.jpg)
#neo4j
Query times proportional to size of subgraph searched
![Page 70: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/70.jpg)
#neo4j
Query times proportional to size of subgraph searched
![Page 71: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/71.jpg)
#neo4j
Query times proportional to size of subgraph searched
![Page 72: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/72.jpg)
#neo4j
Query times remain constant …
![Page 73: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/73.jpg)
#neo4j
… unless subgraph searched grows
![Page 74: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/74.jpg)
#neo4j
Unit test fixture public class ColleagueFinderTest {
private static GraphDatabaseService db;
private static ColleagueFinder finder;
@BeforeClass
public static void init() {
db = new TestGraphDatabaseFactory().newImpermanentDatabase();
ExampleGraph.populate( db );
finder = new ColleagueFinder( db );
}
@AfterClass
public static void shutdown() {
db.shutdown();
}
}
![Page 75: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/75.jpg)
#neo4j
ImpermanentGraphDatabase
• In-memory
• For testing only
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
![Page 76: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/76.jpg)
#neo4j
Create sample data public static void populate( GraphDatabaseService db ) {
ExecutionEngine engine = new ExecutionEngine( db );
String cypher =
"CREATE ian:person VALUES {name:'Ian'},\n" +
" bill:person VALUES {name:'Bill'},\n" +
" lucy:person VALUES {name:'Lucy'},\n" +
" acme:company VALUES {name:'Acme'},\n" +
// Cypher continues...
" (bill)-[:HAS_SKILL]->(neo4j),\n" +
" (bill)-[:HAS_SKILL]->(ruby),\n" +
" (lucy)-[:HAS_SKILL]->(java),\n" +
" (lucy)-[:HAS_SKILL]->(neo4j)";
engine.execute( cypher );
}
![Page 77: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/77.jpg)
#neo4j
Unit test @Test
public void shouldFindColleaguesWithSimilarSkills() throws Exception {
// when
Iterator<Map<String, Object>> results = finder.findFor( "Ian" );
// then
assertEquals( "Lucy", results.next().get( "name" ) );
assertEquals( "Bill", results.next().get( "name" ) );
assertFalse( results.hasNext() );
}
![Page 78: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/78.jpg)
#neo4j
Object under test public class ColleagueFinder {
private final ExecutionEngine cypherEngine;
public ColleagueFinder( GraphDatabaseService db ) {
this.cypherEngine = new ExecutionEngine( db );
}
public Iterator<Map<String, Object>> findFor( String name ) {
...
}
}
![Page 79: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/79.jpg)
#neo4j
findFor() method public Iterator<Map<String, Object>> findFor( String name ) {
String cypher =
"MATCH (me:person)-[:WORKS_FOR]->(company),\n" +
" (me)-[:HAS_SKILL]->(skill),\n" +
" (colleague)-[:WORKS_FOR]->(company),\n" +
" (colleague)-[:HAS_SKILL]->(skill)\n" +
"WHERE me.name = {name}\n" +
"RETURN colleague.name AS name,\n" +
" count(skill) AS score,\n" +
" collect(skill.name) AS skills\n" +
"ORDER BY score DESC";
Map<String, Object> params = new HashMap<String, Object>();
params.put( "name", name );
return cypherEngine.execute( cypher, params ).iterator();
}
![Page 80: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/80.jpg)
#neo4j
Unmanaged extension @Path("/similar-skills")
public class ColleagueFinderExtension {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ColleagueFinder colleagueFinder;
public ColleagueFinderExtension( @Context GraphDatabaseService db ) {
this.colleagueFinder = new ColleagueFinder( db );
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{name}")
public Response getColleagues( @PathParam("name") String name )
throws IOException {
String json = MAPPER
.writeValueAsString( colleagueFinder.findFor( name ) );
return Response.ok().entity( json ).build();
}
}
![Page 81: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/81.jpg)
#neo4j
JAX-RS annotations @Path("/similar-skills")
public class ColleagueFinderExtension {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ColleagueFinder colleagueFinder;
public ColleagueFinderExtension( @Context GraphDatabaseService db ) {
this.colleagueFinder = new ColleagueFinder( db );
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{name}")
public Response getColleagues( @PathParam("name") String name )
throws IOException {
String json = MAPPER
.writeValueAsString( colleagueFinder.findFor( name ) );
return Response.ok().entity( json ).build();
}
}
![Page 82: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/82.jpg)
#neo4j
Map HTTP request to object+method @Path("/similar-skills")
public class ColleagueFinderExtension {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ColleagueFinder colleagueFinder;
public ColleagueFinderExtension( @Context GraphDatabaseService db ) {
this.colleagueFinder = new ColleagueFinder( db );
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{name}")
public Response getColleagues( @PathParam("name") String name )
throws IOException {
String json = MAPPER
.writeValueAsString( colleagueFinder.findFor( name ) );
return Response.ok().entity( json ).build();
}
}
GET /similar-skills /Sue
![Page 83: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/83.jpg)
#neo4j
Database injected by server @Path("/similar-skills")
public class ColleagueFinderExtension {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ColleagueFinder colleagueFinder;
public ColleagueFinderExtension( @Context GraphDatabaseService db ) {
this.colleagueFinder = new ColleagueFinder( db );
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{name}")
public Response getColleagues( @PathParam("name") String name )
throws IOException {
String json = MAPPER
.writeValueAsString( colleagueFinder.findFor( name ) );
return Response.ok().entity( json ).build();
}
}
![Page 84: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/84.jpg)
#neo4j
Generate and format response @Path("/similar-skills")
public class ColleagueFinderExtension {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ColleagueFinder colleagueFinder;
public ColleagueFinderExtension( @Context GraphDatabaseService db ) {
this.colleagueFinder = new ColleagueFinder( db );
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{name}")
public Response getColleagues( @PathParam("name") String name )
throws IOException {
String json = MAPPER
.writeValueAsString( colleagueFinder.findFor( name ) );
return Response.ok().entity( json ).build();
}
}
![Page 85: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/85.jpg)
#neo4j
Extension test fixture public class ColleagueFinderExtensionTest {
private static CommunityNeoServer server;
@BeforeClass
public static void startServer() throws IOException
{
server = CommunityServerBuilder.server()
.withThirdPartyJaxRsPackage(
"org.neo4j.good_practices", "/colleagues" )
.build();
server.start();
ExampleGraph.populate( server.getDatabase().getGraph() );
}
@AfterClass
public static void stopServer() {
server.stop();
}
}
![Page 86: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/86.jpg)
#neo4j
CommunityServerBuilder
• Programmatic configuration
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
</dependency>
![Page 87: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/87.jpg)
#neo4j
Testing extensions @Test
public void shouldReturnColleaguesWithSimilarSkills() throws Exception {
Client client = Client.create( new DefaultClientConfig() );
WebResource resource = client
.resource( "http://localhost:7474/colleagues/similar-skills/Ian" );
ClientResponse response = resource
.accept( MediaType.APPLICATION_JSON )
.get( ClientResponse.class );
List<Map<String, Object>> results = new ObjectMapper()
.readValue(response.getEntity( String.class ), List.class );
// Assertions
...
![Page 88: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/88.jpg)
#neo4j
Testing extensions (continued)
...
assertEquals( 200, response.getStatus() );
assertEquals( MediaType.APPLICATION_JSON,
response.getHeaders().get( "Content-Type" ).get( 0 ) );
assertEquals( "Lucy", results.get( 0 ).get( "name" ) );
assertThat( (Iterable<String>) results.get( 0 ).get( "skills" ),
hasItems( "Java", "Neo4j" ) );
}
![Page 89: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/89.jpg)
#neo4j
Examples to follow
• Neo4j Good Practices Accompanying code for some of the examples in this talk.https://github.com/iansrobinson/neo4j-good-practices
• Cypher-RS A server extension that allows you to configure fixed REST end points for cypher queries. https://github.com/jexp/cypher-rs
![Page 90: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/90.jpg)
#neo4j
Learning More
![Page 92: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/92.jpg)
#neo4j
Neo4j Manual Modeling Examples
Google “neo4j modeling manual”
![Page 93: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/93.jpg)
#neo4j
https://github.com/neo4j-contrib/graphgist/wiki
Cypher Modeling Challenge
![Page 94: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/94.jpg)
#neo4j
Modeling Webinar
Coming soon… (www.neotechnology.com/newsletter or
@neo4j if interested)
![Page 96: Graph Modeling Do's and Don'ts - Patrick Durusau, patrick](https://reader031.fdocuments.net/reader031/viewer/2022021209/62063cc08c2f7b173005bb65/html5/thumbnails/96.jpg)
#neo4j
And that’s it
@markhneedham