testdriven’datamodeling’with’...
TRANSCRIPT
![Page 2: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/2.jpg)
#neo4j
Outline
• Data modeling with graphs • Neo4j applicaDon architecture opDons • TesDng your data model
![Page 3: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/3.jpg)
#neo4j
Graph data modeling
![Page 4: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/4.jpg)
#neo4j
Property Graph Data Model
![Page 5: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/5.jpg)
#neo4j
Models
Images: en.wikipedia.org
![Page 6: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/6.jpg)
#neo4j
User stories
As an employee
I want to know who in the company has similar skills to me
So that we can exchange knowledge
![Page 7: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/7.jpg)
#neo4j
Derive quesDons
Which people, who work for the same company as me, have similar skills to me?
As an employee I want to know who in the company has similar skills to me So that we can exchange knowledge
![Page 8: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/8.jpg)
#neo4j
IdenDfy enDDes
Which people, who work for the same company as me, have similar skills to me? person company skill
![Page 9: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/9.jpg)
#neo4j
IdenDfy relaDonships between enDDes
Which people, who work for the same company as me, have similar skills to me? person WORKS_FOR company person HAS_SKILL skill
![Page 10: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/10.jpg)
#neo4j
Convert to Cypher paths
person WORKS_FOR company person HAS_SKILL skill (person)-[:WORKS_FOR]->(company),(person)-[:HAS_SKILL]->(skill)
![Page 11: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/11.jpg)
#neo4j
Cypher paths (person)-[:WORKS_FOR]->(company),(person)-[:HAS_SKILL]->(skill)
(company)<-[:WORKS_FOR]-(person)-[:HAS_SKILL]->(skill)
![Page 12: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/12.jpg)
#neo4j
Data model
(company)<-[:WORKS_FOR]-(person)-[:HAS_SKILL]->(skill)
![Page 13: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/13.jpg)
#neo4j
FormulaDng quesDon as graph paVern
Which people, who work for the same company as me, have similar skills to me?
![Page 14: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/14.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 skillsORDER BY score DESC
![Page 15: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/15.jpg)
#neo4j
Graph paVern
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 skillsORDER BY score DESC
![Page 16: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/16.jpg)
#neo4j
Anchor paVern 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 skillsORDER BY score DESC
![Page 17: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/17.jpg)
#neo4j
Create projecDon 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 skillsORDER BY score DESC
![Page 18: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/18.jpg)
#neo4j
First match
![Page 19: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/19.jpg)
#neo4j
Second match
![Page 20: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/20.jpg)
#neo4j
Third match
![Page 21: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/21.jpg)
#neo4j
Running the query +-----------------------------------+| name | score | skills |+-----------------------------------+| "Lucy" | 2 | ["Java","Neo4j"] || "Bill" | 1 | ["Neo4j"] |+-----------------------------------+2 rows
![Page 22: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/22.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 skillsORDER BY score DESC
As an employee I want to know who in the company has similar skills to me So that we can exchange knowledge
(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 23: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/23.jpg)
#neo4j
Nodes for things
![Page 24: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/24.jpg)
#neo4j
Labels for grouping
![Page 25: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/25.jpg)
#neo4j
RelaDonships for structure
![Page 26: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/26.jpg)
#neo4j
Don’t model enDDes as relaDonships
• Limits data model evoluDon – Unable to associate more enDDes
• EnDDes someDmes hidden in a verb • Smells: – Lots of aVribute-‐like properDes – Property value redundancy – Heavy use of relaDonship indexes
![Page 27: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/27.jpg)
#neo4j
Example: Reviews
![Page 28: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/28.jpg)
#neo4j
Add another review
![Page 29: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/29.jpg)
#neo4j
And another
![Page 30: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/30.jpg)
#neo4j
Problems • Redundant data (2 x amazon.co.uk)
• Difficult to find reviews for source
• Users can’t comment on reviews
![Page 31: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/31.jpg)
#neo4j
Revised model
![Page 32: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/32.jpg)
#neo4j
Model acDons in terms of products
![Page 33: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/33.jpg)
#neo4j
ApplicaDon architectures
![Page 34: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/34.jpg)
#neo4j
Embedded
• Host in Java process • Access to Java APIs
Java APIs
ApplicaDon
![Page 35: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/35.jpg)
#neo4j
Server
• HTTP/JSON interface • Server wraps embedded instance
REST API REST API REST API
REST Client
ApplicaDon
Write LB Read LB
![Page 36: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/36.jpg)
#neo4j
• Encapsulate complex server-‐side logic • Control HTTP request/response format
Server Extensions
REST API Extensions
![Page 37: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/37.jpg)
#neo4j
TesDng
![Page 38: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/38.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 idenDfy regressions as your data model evolves
• Performance test queries against representaDve dataset
![Page 39: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/39.jpg)
#neo4j
Query Dmes proporDonal to size of subgraph searched
![Page 40: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/40.jpg)
#neo4j
Query Dmes proporDonal to size of subgraph searched
![Page 41: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/41.jpg)
#neo4j
Query Dmes proporDonal to size of subgraph searched
![Page 42: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/42.jpg)
#neo4j
Query Dmes remain constant …
![Page 43: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/43.jpg)
#neo4j
… unless subgraph seached grows
![Page 44: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/44.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 45: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/45.jpg)
#neo4j
Create database 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 46: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/46.jpg)
#neo4j
Populate graph 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 47: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/47.jpg)
#neo4j
Create object under test 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(); }}
Inject database
![Page 48: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/48.jpg)
#neo4j
ImpermanentGraphDatabase • In-‐memory • For tesDng only <dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j-kernel</artifactId> <version>${project.version}</version> <type>test-jar</type> <scope>test</scope> </dependency>
![Page 49: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/49.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 50: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/50.jpg)
#neo4j
Unit test @Testpublic 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 51: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/51.jpg)
#neo4j
Execute unit under test @Testpublic 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 52: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/52.jpg)
#neo4j
Assert results @Testpublic 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 53: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/53.jpg)
#neo4j
Ensure no more results @Testpublic 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 54: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/54.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 55: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/55.jpg)
#neo4j
Inject database 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 56: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/56.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 57: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/57.jpg)
#neo4j
Cypher query 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 58: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/58.jpg)
#neo4j
Parameterized query 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 59: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/59.jpg)
#neo4j
Execute query 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 60: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/60.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 61: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/61.jpg)
#neo4j
JAX-‐RS annotaDons @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 62: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/62.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 63: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/63.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 64: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/64.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 65: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/65.jpg)
#neo4j
Extension test fixture public class ColleagueFinderExtensionTest { private static CommunityNeoServer server; @BeforeClass public static void startServer() throws IOException { server = ServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @AfterClass public static void stopServer() { server.stop(); }}
![Page 66: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/66.jpg)
#neo4j
Build and configure server public class ColleagueFinderExtensionTest { private static CommunityNeoServer server; @BeforeClass public static void startServer() throws IOException { server = ServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @AfterClass public static void stopServer() { server.stop(); }}
![Page 67: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/67.jpg)
#neo4j
Start server public class ColleagueFinderExtensionTest { private static CommunityNeoServer server; @BeforeClass public static void startServer() throws IOException { server = ServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @AfterClass public static void stopServer() { server.stop(); }}
![Page 68: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/68.jpg)
#neo4j
Populate database public class ColleagueFinderExtensionTest { private static CommunityNeoServer server; @BeforeClass public static void startServer() throws IOException { server = ServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @AfterClass public static void stopServer() { server.stop(); }}
![Page 69: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/69.jpg)
#neo4j
ServerBuilder • ProgrammaDc configuraDon <dependency> <groupId>org.neo4j.app</groupId> <artifactId>neo4j-server</artifactId> <version>${project.version}</version> <type>test-jar</type> </dependency>
![Page 70: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/70.jpg)
#neo4j
TesDng extensions @Testpublic 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 71: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/71.jpg)
#neo4j
Create HTTP client @Testpublic 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 72: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/72.jpg)
#neo4j
Issue request @Testpublic 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 73: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/73.jpg)
#neo4j
Parse response @Testpublic 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 74: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/74.jpg)
#neo4j
Assert results ... 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 75: TestDriven’DataModeling’With’ Graphsnosqlroadshow.com/dl/.../TestDrivenDataModeling_Ian_Robinson.pdf · #neo4j’ Create’sample’data public static void populate( GraphDatabaseService](https://reader034.vdocuments.net/reader034/viewer/2022042310/5ed72c4cc30795314c175502/html5/thumbnails/75.jpg)
#neo4j hVp://graphdatabases.com
Ian Robinson, Jim Webber & Emil Eifrem
Graph Databases
h
Compliments
of Neo Technology
Thank you @ianSrobinson
[email protected] github.com/iansrobinson