-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathvalidate.py
More file actions
198 lines (176 loc) · 7.69 KB
/
Copy pathvalidate.py
File metadata and controls
198 lines (176 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""Runs the article's code verbatim against a real Neo4j and prints the output.
This exists so no snippet in the handbook is theoretical. Every query below is
copied from the article, and the terminal output of this script is what gets
screenshotted. If a claim in the article is wrong, this fails.
docker run -d --name neo4j-fcc -p 7474:7474 -p 7687:7687 \
-e NEO4J_AUTH=neo4j/testpassword123 neo4j:5
python3 docs/growth/freecodecamp/knowledge-graph-python-neo4j/validate.py
"""
import os
from neo4j import GraphDatabase
URI = os.environ.get("NEO4J_URI", "neo4j://localhost:7687")
AUTH = (os.environ.get("NEO4J_USER", "neo4j"), os.environ.get("NEO4J_PASSWORD", "testpassword123"))
CONSTRAINTS = [
"CREATE CONSTRAINT engineer_email IF NOT EXISTS FOR (e:Engineer) REQUIRE e.email IS UNIQUE",
"CREATE CONSTRAINT service_name IF NOT EXISTS FOR (s:Service) REQUIRE s.name IS UNIQUE",
"CREATE CONSTRAINT incident_ref IF NOT EXISTS FOR (i:Incident) REQUIRE i.ref IS UNIQUE",
"CREATE CONSTRAINT team_name IF NOT EXISTS FOR (t:Team) REQUIRE t.name IS UNIQUE",
]
OWNERSHIP = [
{"email": "ada@example.com", "name": "Ada Okonjo", "service": "payments", "team": "Platform"},
{"email": "grace@example.com", "name": "Grace Lin", "service": "payments", "team": "Platform"},
{"email": "linus@example.com", "name": "Linus Berg", "service": "checkout", "team": "Commerce"},
{"email": "mira@example.com", "name": "Mira Haddad", "service": "auth", "team": "Platform"},
{"email": "tom@example.com", "name": "Tom Ferreira", "service": "search", "team": "Discovery"},
]
DEPENDENCIES = [
{"upstream": "auth", "downstream": "payments"},
{"upstream": "auth", "downstream": "checkout"},
{"upstream": "payments", "downstream": "checkout"},
{"upstream": "search", "downstream": "checkout"},
]
INCIDENTS = [
{"ref": "INC-4471", "summary": "Elevated 5xx on card capture", "services": ["payments", "checkout"]},
]
def banner(t):
print("\n" + "=" * 74)
print(t)
print("=" * 74)
def main():
with GraphDatabase.driver(URI, auth=AUTH) as driver:
driver.verify_connectivity()
print("Connected to", URI)
banner("1. Constraints (creates the supporting index at the same time)")
for statement in CONSTRAINTS:
driver.execute_query(statement, database_="neo4j")
print(" OK ", statement.split(" IF NOT EXISTS")[0])
banner("2. Bulk load with UNWIND, one round trip")
driver.execute_query("MATCH (n) DETACH DELETE n", database_="neo4j")
_, summary, _ = driver.execute_query(
"""
UNWIND $rows AS row
MERGE (e:Engineer {email: row.email})
SET e.name = row.name
MERGE (s:Service {name: row.service})
MERGE (t:Team {name: row.team})
MERGE (e)-[:OWNS]->(s)
MERGE (e)-[:MEMBER_OF]->(t)
""",
rows=OWNERSHIP, database_="neo4j",
)
c = summary.counters
print(f" nodes created: {c.nodes_created} relationships created: {c.relationships_created}")
print(f" properties set: {c.properties_set}")
driver.execute_query(
"""
UNWIND $rows AS row
MATCH (u:Service {name: row.upstream}), (d:Service {name: row.downstream})
MERGE (d)-[:DEPENDS_ON]->(u)
""",
rows=DEPENDENCIES, database_="neo4j",
)
driver.execute_query(
"""
UNWIND $rows AS row
MERGE (i:Incident {ref: row.ref}) SET i.summary = row.summary
WITH i, row
UNWIND row.services AS svc
MATCH (s:Service {name: svc})
MERGE (i)-[:AFFECTS]->(s)
""",
rows=INCIDENTS, database_="neo4j",
)
print(" dependencies and incident loaded")
banner("3. MERGE is idempotent: run the same load again")
_, summary2, _ = driver.execute_query(
"""
UNWIND $rows AS row
MERGE (e:Engineer {email: row.email})
SET e.name = row.name
MERGE (s:Service {name: row.service})
MERGE (e)-[:OWNS]->(s)
""",
rows=OWNERSHIP, database_="neo4j",
)
c2 = summary2.counters
print(f" nodes created this time: {c2.nodes_created} relationships created: {c2.relationships_created}")
print(" (both zero, which is the whole point of MERGE)")
banner("4. The multi-hop query: who has context on INC-4471?")
records, summary3, _ = driver.execute_query(
"""
MATCH (i:Incident {ref: $ref})-[:AFFECTS]->(:Service)<-[:OWNS]-(e:Engineer)
RETURN DISTINCT e.name AS name, e.email AS email
ORDER BY name
""",
ref="INC-4471", database_="neo4j",
)
for r in records:
print(f" {r['name']:<16} {r['email']}")
print(f" -> {len(records)} engineers, {summary3.result_available_after} ms to first result")
banner("5. Four hops: whole teams behind the affected services")
records, _, _ = driver.execute_query(
"""
MATCH (i:Incident {ref: $ref})-[:AFFECTS]->(:Service)<-[:OWNS]-(:Engineer)
-[:MEMBER_OF]->(t:Team)<-[:MEMBER_OF]-(e:Engineer)
RETURN DISTINCT t.name AS team, e.name AS name
ORDER BY team, name
""",
ref="INC-4471", database_="neo4j",
)
for r in records:
print(f" {r['team']:<12} {r['name']}")
banner("6. Variable length path: everything downstream of an auth failure")
records, _, _ = driver.execute_query(
"""
MATCH (s:Service {name: $name})<-[:DEPENDS_ON*1..4]-(affected:Service)
RETURN DISTINCT affected.name AS affected ORDER BY affected
""",
name="auth", database_="neo4j",
)
print(" auth breaks ->", ", ".join(r["affected"] for r in records))
banner("7. Aggregation: services per team")
records, _, _ = driver.execute_query(
"""
MATCH (t:Team)<-[:MEMBER_OF]-(:Engineer)-[:OWNS]->(s:Service)
RETURN t.name AS team, count(DISTINCT s) AS services
ORDER BY services DESC, team
""",
database_="neo4j",
)
for r in records:
print(f" {r['team']:<12} {r['services']}")
banner("8. OPTIONAL MATCH keeps engineers who own nothing")
driver.execute_query(
"MERGE (e:Engineer {email: $email}) SET e.name = $name",
email="new@example.com", name="Nadia Rossi", database_="neo4j",
)
records, _, _ = driver.execute_query(
"""
MATCH (e:Engineer)
OPTIONAL MATCH (e)-[:OWNS]->(s:Service)
RETURN e.name AS name, collect(s.name) AS services
ORDER BY name
""",
database_="neo4j",
)
for r in records:
print(f" {r['name']:<16} {r['services']}")
banner("9. Graph totals")
records, _, _ = driver.execute_query(
"""
MATCH (n) WITH labels(n)[0] AS label, count(*) AS c
RETURN label, c ORDER BY c DESC, label
""",
database_="neo4j",
)
for r in records:
print(f" {r['label']:<12} {r['c']}")
records, _, _ = driver.execute_query(
"MATCH ()-[r]->() RETURN type(r) AS rel, count(*) AS c ORDER BY c DESC, rel",
database_="neo4j",
)
for r in records:
print(f" {r['rel']:<12} {r['c']}")
print("\nAll steps completed against a real Neo4j instance.\n")
if __name__ == "__main__":
main()