Test%Driven+Data+Modeling+With+Graphs + Twi7er:+@ianSrobinson+ - - PowerPoint PPT Presentation

test driven data modeling with graphs
SMART_READER_LITE
LIVE PREVIEW

Test%Driven+Data+Modeling+With+Graphs + Twi7er:+@ianSrobinson+ - - PowerPoint PPT Presentation

Test%Driven+Data+Modeling+With+Graphs + Twi7er:+@ianSrobinson+ #neo4j+ + Outline+ Data+modeling+with+graphs+ Neo4j+applicaDon+architecture+opDons+ TesDng+your+data+model++ Graph+data+modeling+ Labeled+Property+Graph+ Models+


slide-1
SLIDE 1

Test%Driven+Data+Modeling+With+Graphs+

Twi7er:+@ianSrobinson+ #neo4j+ +

slide-2
SLIDE 2

Outline+

  • Data+modeling+with+graphs+
  • Neo4j+applicaDon+architecture+opDons+
  • TesDng+your+data+model++
slide-3
SLIDE 3

Graph+data+modeling+

slide-4
SLIDE 4

Labeled+Property+Graph+

slide-5
SLIDE 5

Models+

Images:+en.wikipedia.org+

Purposeful+abstracDon+of+a+domain+designed+to+ saDsfy+parDcular+applicaDon/end%user+goals+

slide-6
SLIDE 6

Example+ApplicaDon+

  • Knowledge+management+

– People,+companies,+skills+ – Cross+organizaDonal+

  • Find+my+professional+social+network+

– Exchange+knowledge+ – Interest+groups+ – Help+ – Staff+projects+

slide-7
SLIDE 7

ApplicaDon/End%User+Goals+

As#an#employee'

'

I#want#to'know'who'in'the'company' has'similar'skills'to'me'

'

So#that#we'can'exchange'knowledge'

slide-8
SLIDE 8

QuesDons+To+Ask+of+the+Domain+

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'

slide-9
SLIDE 9

IdenDfy+EnDDes+

Which+people,+who+work+for+the+same+company+ as+me,+have+similar+skills+to+me?+ + Person+ Company+ Skill+

slide-10
SLIDE 10

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+

slide-11
SLIDE 11

Convert+to+Cypher+Paths+

Person+WORKS_FOR+Company+ Person+HAS_SKILL+Skill+

RelaDonship+ Label+

(:Person)-[:WORKS_FOR]->(:Company), (:Person)-[:HAS_SKILL]->(:Skill)

slide-12
SLIDE 12

Consolidate+Paths+

(:Person)-[:WORKS_FOR]->(:Company), (:Person)-[:HAS_SKILL]->(:Skill)

(:Company)<-[:WORKS_FOR]-(:Person)-[:HAS_SKILL]->(:Skill)

slide-13
SLIDE 13

Candidate+Data+Model+

(:Company)<-[:WORKS_FOR]-(:Person)-[:HAS_SKILL]->(:Skill)

slide-14
SLIDE 14

Express+QuesDon+as+Graph+Pa7ern+

Which+people,+who+work+for+the+same+company+ as+me,+have+similar+skills+to+me?+

slide-15
SLIDE 15

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

slide-16
SLIDE 16

Graph+Pa7ern+

Which+people,+who+work+for+the+same+company+ as+me,+have+similar+skills+to+me?+

MATCH (company)<-[:WORKS_FOR]-( MATCH (company)<-[:WORKS_FOR]-(me:Person me:Person)-[:HAS_SKILL]->(skill), )-[:HAS_SKILL]->(skill), (company)<-[:WORKS_FOR]-(colleague)-[: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

slide-17
SLIDE 17

Which+people,+who+work+for+the+same+company+ as+me,+have+similar+skills+to+me?+

MATCH (company)<-[:WORKS_FOR]-(me:Person me:Person)-[:HAS_SKILL]->(skill), (company)<-[:WORKS_FOR]-(colleague)-[:HAS_SKILL]->(skill) WHERE WHERE me.name me.name = {name} = {name} RETURN colleague.name AS name, count(skill) AS score, collect(skill.name) AS skills ORDER BY score DESC

Anchor+Pa7ern+in+Graph+

Search+nodes+labeled+ ‘Person’,+matching+on+ ‘name’+property+

slide-18
SLIDE 18

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 RETURN colleague.name colleague.name AS name, AS name, count(skill) AS score, count(skill) AS score, collect( collect(skill.name skill.name) AS skills ) AS skills ORDER BY score DESC ORDER BY score DESC

slide-19
SLIDE 19

First+Match+

slide-20
SLIDE 20

Second+Match+

slide-21
SLIDE 21

Third+Match+

slide-22
SLIDE 22

Running+the+Query+

+-----------------------------------+ | name | score | skills | +-----------------------------------+ | "Lucy" | 2 | ["Java","Neo4j"] | | "Bill" | 1 | ["Neo4j"] | +-----------------------------------+ 2 rows

slide-23
SLIDE 23

From+User+Story+to+Model+and+Query+

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 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?

slide-24
SLIDE 24

TesDng+

slide-25
SLIDE 25

Why+Test?+

  • Ensure+model+is+fit+for+queries+

– Rapid+feedback+

  • Ensure+correctness+of+queries+
  • Document+your+understanding+of+your+domain+

– Including+corner+cases+and+excepDons+

  • Provide+a+regression+test+suite+

– Allows+you+to+change+and+evolve+model+and+ queries+

slide-26
SLIDE 26

Method+

  • Develop+queries,+or+classes+that+encapsulate+

queries,+using+unit'tests'

  • Use+small,'well7understood'datasets+in+each+test+

– Create+data+in+test+setup+ – Test+dataset+expresses+your+understanding+of+(part+of)+ the+domain+

  • Inject+in7memory'graph'database'(or+Cypher+

engine)+into+object+under+test+

  • The+exact+strategy+you+use+depends+on+your+

applicaDon+architecture…+

slide-27
SLIDE 27

ApplicaDon+Architectures+

  • Embedded+
  • Server+
  • Server+with+Extensions+
slide-28
SLIDE 28

ApplicaDon+Architectures+

  • Embedded+

– Host+in+Java+process+ – Access+to+Java+APIs+

  • Server+
  • Server+with+Extensions+

Java+APIs+ ApplicaDon+

slide-29
SLIDE 29

ApplicaDon+Architectures+

  • Embedded+
  • Server+

– HTTP/JSON+interface+ – Server+wraps+embedded+ instance+

  • Server+with+Extensions+

REST+API+ REST+API+ REST+API+ REST+Client+ ApplicaDon+ Write+LB+ Read+LB+

slide-30
SLIDE 30

ApplicaDon+Architectures+

  • Embedded+
  • Server+
  • Server+with+Extensions+

– Execute+complex+logic+on+server+ – Control+HTTP+request/response+format+

REST+API+ Extensions+

slide-31
SLIDE 31

Embedded+Example+

  • Company+social+network+
  • Find+colleagues+with+similar+skills+
  • Encapsulate+query+in+a+ColleagueFinder
slide-32
SLIDE 32

Unit+Test+Fixture+

public class ColleagueFinderTest { private GraphDatabaseService db; private ColleagueFinder finder; @Before public void init() { db = new TestGraphDatabaseFactory().newImpermanentDatabase(); ExampleGraph.populate( db ); finder = new ColleagueFinder( new ExecutionEngine( db ) ); } @After public void shutdown() { db.shutdown(); } }

slide-33
SLIDE 33

Create+Database+

public class ColleagueFinderTest { private private GraphDatabaseService GraphDatabaseService db db; private ColleagueFinder finder; @Before public void init() { db db = new = new TestGraphDatabaseFactory TestGraphDatabaseFactory(). ().newImpermanentDatabase newImpermanentDatabase(); (); ExampleGraph.populate( db ); finder = new ColleagueFinder( new ExecutionEngine( db ) ); } @After public void shutdown() { db.shutdown(); } }

slide-34
SLIDE 34

Populate+Graph+

public class ColleagueFinderTest { private GraphDatabaseService db; private ColleagueFinder finder; @Before public void init() { db = new TestGraphDatabaseFactory().newImpermanentDatabase(); ExampleGraph.populate ExampleGraph.populate( ( db db ); ); finder = new ColleagueFinder( new ExecutionEngine( db ) ); } @After public void shutdown() { db.shutdown(); } }

slide-35
SLIDE 35

Create+Object+Under+Test+

public class ColleagueFinderTest { private GraphDatabaseService db; private private ColleagueFinder ColleagueFinder finder; finder; @Before public void init() { db = new TestGraphDatabaseFactory().newImpermanentDatabase(); ExampleGraph.populate( db ); finder = new finder = new ColleagueFinder ColleagueFinder( new ( new ExecutionEngine ExecutionEngine( ( db db ) ); ) ); } @After public void shutdown() { db.shutdown(); } }

Inject++ ExecuDonEngine+

slide-36
SLIDE 36

ImpermanentGraphDatabase+

  • In%memory+
  • For+tesDng+only,+not+producDon!+

<dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j-kernel</artifactId> <version>${project.version}</version> <type>test-jar</type> <scope>test</scope> </dependency>

slide-37
SLIDE 37

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

slide-38
SLIDE 38

Unit+Test+

@Test public void shouldFindColleaguesWithSimilarSkills() throws Exception { // when Iterator<Map<String, Object>> results = finder.findColleaguesFor( "Ian" ); // then assertEquals( "Lucy", results.next().get( "name" ) ); assertEquals( "Bill", results.next().get( "name" ) ); assertFalse( results.hasNext() ); }

slide-39
SLIDE 39

Execute+Object+Under+Test+

@Test public void shouldFindColleaguesWithSimilarSkills() throws Exception { // when Iterator<Map<String, Object>> results = Iterator<Map<String, Object>> results = finder.findColleaguesFor finder.findColleaguesFor( "Ian" ); ( "Ian" ); // then assertEquals( "Lucy", results.next().get( "name" ) ); assertEquals( "Bill", results.next().get( "name" ) ); assertFalse( results.hasNext() ); }

slide-40
SLIDE 40

Assert+Results+

@Test public void shouldFindColleaguesWithSimilarSkills() throws Exception { // when Iterator<Map<String, Object>> results = finder.findColleaguesFor( "Ian" ); // then assertEquals assertEquals( "Lucy", ( "Lucy", results.next results.next().get( "name" ) ); ().get( "name" ) ); assertEquals assertEquals( "Bill", ( "Bill", results.next results.next().get( "name" ) ); ().get( "name" ) ); assertFalse( results.hasNext() ); }

slide-41
SLIDE 41

Ensure+No+More+Results+

@Test public void shouldFindColleaguesWithSimilarSkills() throws Exception { // when Iterator<Map<String, Object>> results = finder.findColleaguesFor( "Ian" ); // then assertEquals( "Lucy", results.next().get( "name" ) ); assertEquals( "Bill", results.next().get( "name" ) ); assertFalse assertFalse( ( results.hasNext results.hasNext() ); () ); }

slide-42
SLIDE 42

ColleagueFinder+

public class ColleagueFinder { private final ExecutionEngine executionEngine; public ColleagueFinder( ExecutionEngine executionEngine ) { this.executionEngine = executionEngine; } public Iterator<Map<String, Object>> findColleaguesFor( String name ) { ... } }

slide-43
SLIDE 43

Inject+ExecuDonEngine+

public class ColleagueFinder { private final private final ExecutionEngine ExecutionEngine executionEngine executionEngine; public ColleagueFinder( ExecutionEngine ExecutionEngine executionEngine executionEngine ) { this.executionEngine this.executionEngine = = executionEngine executionEngine; } public Iterator<Map<String, Object>> findColleaguesFor( String name ) { ... } }

slide-44
SLIDE 44

findColleaguesFor()+Method+

public Iterator<Map<String, Object>> findColleaguesFor( 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 executionEngine.execute( cypher, params ).iterator(); }

slide-45
SLIDE 45

Cypher+Query+

public Iterator<Map<String, Object>> findColleaguesFor( String name ) { String cypher = String cypher = "MATCH ( "MATCH (me:Person me:Person)-[:WORKS_FOR]->(company),\n" + )-[:WORKS_FOR]->(company),\n" + " (me)-[:HAS_SKILL]->(skill),\n" + " (me)-[:HAS_SKILL]->(skill),\n" + " (colleague)-[:WORKS_FOR]->(company),\n" + " (colleague)-[:WORKS_FOR]->(company),\n" + " (colleague)-[:HAS_SKILL]->(skill)\n" + " (colleague)-[:HAS_SKILL]->(skill)\n" + "WHERE "WHERE me.name me.name = {name}\n" + = {name}\n" + "RETURN "RETURN colleague.name colleague.name AS name,\n" + AS name,\n" + " count(skill) AS score,\n" + " count(skill) AS score,\n" + " collect( " collect(skill.name skill.name) AS skills\n" + ) AS skills\n" + "ORDER BY score DESC"; "ORDER BY score DESC"; Map<String, Object> params = new HashMap<String, Object>(); params.put( "name", name ); return executionEngine.execute( cypher, params ).iterator(); }

slide-46
SLIDE 46

Parameterized+Query+

public Iterator<Map<String, Object>> findColleaguesFor( 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} {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> Map<String, Object> params params = new = new HashMap HashMap<String, Object>(); <String, Object>(); params.put params.put( "name", name ); ( "name", name ); return executionEngine.execute( cypher, params ).iterator(); }

slide-47
SLIDE 47

Execute+Query+

public Iterator<Map<String, Object>> findColleaguesFor( 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 return executionEngine.execute executionEngine.execute( cypher, ( cypher, params params ).iterator(); ).iterator(); }

slide-48
SLIDE 48

Server+Extension+Example+

  • Same+data+mode+and+query+as+before+
  • This+Dme,+we’ll+host+ColleagueFinder+in+a+

server+extension+

slide-49
SLIDE 49

Server+Extension+

@Path("/similar-skills") public class ColleagueFinderExtension { private static final ObjectMapper MAPPER = new ObjectMapper(); private final ColleagueFinder colleagueFinder; public ColleagueFinderExtension( @Context CypherExecutor cypherExecutor ) { this.colleagueFinder = new ColleagueFinder( cypherExecutor.getExecutionEngine() ); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}") public Response getColleagues( @PathParam("name") String name ) throws IOException { String json = MAPPER .writeValueAsString( colleagueFinder.findColleaguesFor( name ) ); return Response.ok().entity( json ).build(); } }

slide-50
SLIDE 50

JAX%RS+AnnotaDons+

@Path("/similar-skills") @Path("/similar-skills") public class ColleagueFinderExtension { private static final ObjectMapper MAPPER = new ObjectMapper(); private final ColleagueFinder colleagueFinder; public ColleagueFinderExtension( @Context CypherExecutor cypherExecutor ) { this.colleagueFinder = new ColleagueFinder( cypherExecutor.getExecutionEngine() ); } @GET @GET @Produces( @Produces(MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON) @Path("/{name}") @Path("/{name}") public Response getColleagues( @PathParam PathParam("name") ("name") String name ) throws IOException { String json = MAPPER .writeValueAsString( colleagueFinder.findColleaguesFor( name ) ); return Response.ok().entity( json ).build(); } }

slide-51
SLIDE 51

Map+HTTP+Request+to+Object+++Method+

@Path("/similar-skills") @Path("/similar-skills") public class ColleagueFinderExtension { private static final ObjectMapper MAPPER = new ObjectMapper(); private final ColleagueFinder colleagueFinder; public ColleagueFinderExtension( @Context CypherExecutor cypherExecutor ) { this.colleagueFinder = new ColleagueFinder( cypherExecutor.getExecutionEngine() ); } @GET @GET @Produces( @Produces(MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON) @Path("/{name}") @Path("/{name}") public Response getColleagues( @PathParam PathParam("name") ("name") String name ) throws IOException { String json = MAPPER .writeValueAsString( colleagueFinder.findColleaguesFor( name ) ); return Response.ok().entity( json ).build(); } }

GET+ /similar%skills+ /Ian+

slide-52
SLIDE 52

CypherExecutor+Injected+by+Server+

@Path("/similar-skills") public class ColleagueFinderExtension { private static final ObjectMapper MAPPER = new ObjectMapper(); private final private final ColleagueFinder ColleagueFinder colleagueFinder colleagueFinder; public ColleagueFinderExtension( @Context @Context CypherExecutor CypherExecutor cypherExecutor cypherExecutor ) { this.colleagueFinder this.colleagueFinder = new = new ColleagueFinder ColleagueFinder( ( cypherExecutor.getExecutionEngine cypherExecutor.getExecutionEngine() ); () ); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}") public Response getColleagues( @PathParam("name") String name ) throws IOException { String json = MAPPER .writeValueAsString( colleagueFinder.findColleaguesFor( name ) ); return Response.ok().entity( json ).build(); } }

Ensures+ ExecuDonEngine+ reused+across+ resource+instances+

slide-53
SLIDE 53

Generate+and+Format+Response+

@Path("/similar-skills") public class ColleagueFinderExtension { private static final private static final ObjectMapper ObjectMapper MAPPER = new MAPPER = new ObjectMapper ObjectMapper(); (); private final ColleagueFinder colleagueFinder; public ColleagueFinderExtension( @Context CypherExecutor cypherExecutor ) { this.colleagueFinder = new ColleagueFinder( cypherExecutor.getExecutionEngine() ); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{name}") public Response getColleagues( @PathParam("name") String name ) throws IOException { String String json json = MAPPER = MAPPER . .writeValueAsString writeValueAsString( ( colleagueFinder.findColleaguesFor colleagueFinder.findColleaguesFor( name ) ); ( name ) ); return return Response.ok Response.ok().entity( ().entity( json json ).build(); ).build(); } }

slide-54
SLIDE 54

Extension+Test+Fixture+

public class ColleagueFinderExtensionTest { private CommunityNeoServer server; @Before public void startServer() throws IOException { server = CommunityServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @After public void stopServer() { server.stop(); } }

slide-55
SLIDE 55

Build+and+Configure+Server+

public class ColleagueFinderExtensionTest { private private CommunityNeoServer CommunityNeoServer server; server; @Before public void startServer() throws IOException { server = server = CommunityServerBuilder.server CommunityServerBuilder.server() () . .withThirdPartyJaxRsPackage withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) "org.neo4j.good_practices", "/colleagues" ) .build(); .build(); server.start(); ExampleGraph.populate( server.getDatabase().getGraph() ); } @After public void stopServer() { server.stop(); } }

slide-56
SLIDE 56

Start+Server+

public class ColleagueFinderExtensionTest { private CommunityNeoServer server; @Before public void startServer() throws IOException { server = CommunityServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start server.start(); (); ExampleGraph.populate( server.getDatabase().getGraph() ); } @After public void stopServer() { server.stop(); } }

slide-57
SLIDE 57

Populate+Database+

public class ColleagueFinderExtensionTest { private CommunityNeoServer server; @Before public void startServer() throws IOException { server = CommunityServerBuilder.server() .withThirdPartyJaxRsPackage( "org.neo4j.good_practices", "/colleagues" ) .build(); server.start(); ExampleGraph.populate ExampleGraph.populate( ( server.getDatabase server.getDatabase(). ().getGraph getGraph() ); () ); } @After public void stopServer() { server.stop(); } }

slide-58
SLIDE 58

CommunityServerBuilder+

  • ProgrammaDc+configuraDon+

<dependency> <groupId>org.neo4j.app</groupId> <artifactId>neo4j-server</artifactId> <version>${project.version}</version> <type>test-jar</type> </dependency>

slide-59
SLIDE 59

TesDng+Extension+Using+HTTP+Client+

@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 ...

slide-60
SLIDE 60

Create+HTTP+Client+

@Test public void shouldReturnColleaguesWithSimilarSkills() throws Exception { Client client = Client client = Client.create Client.create( new ( new DefaultClientConfig 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 ...

slide-61
SLIDE 61

Issue+Request+

@Test public void shouldReturnColleaguesWithSimilarSkills() throws Exception { Client client = Client.create( new DefaultClientConfig() ); WebResource WebResource resource = client resource = client .resource( "http://localhost:7474/colleagues/similar-skills/Ian" ); .resource( "http://localhost:7474/colleagues/similar-skills/Ian" ); ClientResponse ClientResponse response = resource response = resource .accept( .accept( MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON ) ) .get( .get( ClientResponse.class ClientResponse.class ); ); List<Map<String, Object>> results = new ObjectMapper() .readValue(response.getEntity( String.class ), List.class ); // Assertions ...

slide-62
SLIDE 62

Parse+Response+

@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 List<Map<String, Object>> results = new ObjectMapper ObjectMapper() () . .readValue readValue(response.getEntity response.getEntity( ( String.class String.class ), ), List.class List.class ); ); // Assertions ...

slide-63
SLIDE 63

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

slide-64
SLIDE 64

Thank+you+

Twi7er:+@ianSrobinson+ #neo4j+ + + +

Ian Robinson, Jim Webber & Emil Eifrem

Graph Databases h

Compliments

  • f Neo Technology

github.com/iansrobinson/neo4j%good%pracDces+ +