Table of Contents

Graph Data Modeling

Tip: Make the implicit explicit

78r0MgH0u0w

4yh0nzv.jpg

Common nouns ⇒ Labels

Verbs that take an object ⇒ Relationships

Proper noun ⇒ Node with properties

Attirbutes: Property or Relationship?

Use Relationships When...

You need to specify the weight, strength, or some other quality of the relationship:

AND/OR

Attribute value comprises a complex value type:

AND/OR

Attribute values are interconnected:

Modeling Skills as Nodes

satllqh.jpg

Common Graph Structures

Rich Context, Multiple Dimensions

kjhegb8.jpg

Trap: Verbing

Example: [:EMAILED] to (:Email)

hyhldvf.jpg

vodmarb.jpg

Considerations

Linked List

Linked List

gh9hvas.jpg

Interleaved Linked Lists

cjzt6py.jpg

Pointers to Head and Tail

7vpncqh.jpg

Versioning Graphs

Seprate Structure from State

Return Results

jkqi7dx.jpg

MATCH (s:Shop{shop_id:1})-[r1:SELLS]->(p:Product)
WHERE (r1.from <= 1391558400000 AND r1.to > 1391558400000)
MATCH (p)-[r2:STATE]->(ps:ProductState)
WHERE (r2.from <= 1391558400000 AND r2.to > 1391558400000)
RETURN p.product_id AS productId,
       ps.name AS product,
       ps.price AS price
ORDER BY price DESC

Considerations

Refactoring

Definition

Reasons

Data Migrations

Extract Node From Relationship

Problem

Solution

MATCH (a:User)-[r:EMAILED]->(b:User)
WITH a, r, b LIMIT 2
CREATE (email:Email{content:r.content})
MERGE (a)-[:SENT]->(email)-[:TO]->(b)
DELETE r
RETURN count(r) AS numberDeleted

Find similar groups to Neo4j

MATCH (group:Group {name:"Neo4j - London User Group"})-[:HAS_TOPIC]->(topic)<-[:HAS_TOPIC]-(otherGroup)
RETURN otherGroup.name,
       COUNT(topic) AS topicsInCommon,
       COLLECT(topic.name) as topics
ORDER BY topicsInCommon DESC, otherGroup.name
LIMIT 10

Exclude groups I'm a member of

MATCH (group:Group {name:"Neo4j - London User Group"})-[:HAS_TOPIC]->(topic)<-[:HAS_TOPIC]-(otherGroup)
WHERE NOT ((:Member {name:"Mark Needham"})-[:MEMBER_OF]->(otherGroup))
RETURN otherGroup.name,
       COUNT(topic) AS topicsInCommon,
       COLLECT(topic.name) as topics
ORDER BY topicsInCommon DESC, otherGroup.name
LIMIT 10

What is Jonny interested in?

MATCH (m:Member)-[:MEMBER_OF]->(group)-[:HAS_TOPIC]->(topic)
WITH m, topic, COUNT(*) AS times
WHERE times > 3

MERGE (m)-[:INTERESTED_IN]->(topic)

Facts can become nodes

9ncu8zf.jpg

Refactors to facts

MATCH (member:Member)-[rel:MEMBER_OF]->(group)

MERGE (memebership:Membership {id: member.id + "_" + group.id})
SET membership.joind = rel.joined

MERGE (member)-[:HAS_MEMBERSHIP]->(membership)
MERGE (membership)-[:OF_GROUP]->(group)

MATCH (member:Member)-[:HAS_MEMBERSHIP]->(membership)

WITH member, membership ORDER BY member.id, membership.joined

WITH member, COLLECT(membership) AS memberships
UNWIND RANGE(0,SIZE(memberships) - 2) as idx

WITH memberships[idx] AS m1, memberships[idx+1] AS me
MERGE (m1)-[:NEXT]->(m2)

Find next group people join

MATCH (group:Group {name:"Neo4j"})<-[:OF_GROUP]-(membership)-[:NEXT]->(nextMembership),
      (membership)<-[:HAS_MEMBERSHIP]-(member:Member)-[:HAS_MEMBERSHIP]->(nextMembership),
      (nextMembership)-[:OF_GROUP]->(nextGroup)
RETURN nextGroup.name COUNT(*) AS times
ORDER BY times DESC

Docs

Test Driven Data Modeling
TigerGraph

Refs