# KG: neo4j & Python application 101 ### Part 1 neo4j 資料庫 step 1: 建立資料庫 https://neo4j.com/cloud/platform/aura-graph-database/ step 2: 下載 credential 資料 並存放在你的工作資料夾. 如果你下載上述連線資訊,這是你唯一次看到 password 的機會!! step 3: 安裝 neo4j 套件 instal drivers: ``` pip install neo4j pip install python-dotenv ``` step 4: 連線測試 setup.py ```python= # Syntax for Connect to neo4j database # from neo4j import GraphDatabase # URI = "<URI for Neo4j database>" # AUTH = ("<Username>", "<Password>") import dotenv import os from neo4j import GraphDatabase load_status = dotenv.load_dotenv("Neo4j-AURA_instanceID-created-date.txt") if load_status is False: raise RuntimeError('Environment variables not loaded.') URI = os.getenv("NEO4J_URI") AUTH = (os.getenv("NEO4J_USERNAME"), os.getenv("NEO4J_PASSWORD")) with GraphDatabase.driver(URI, auth=AUTH) as driver: driver.verify_connectivity() ``` ### Part 2 #### 範例1 Create, Read, Update, Delete crud.py ```python= import dotenv import os from neo4j import GraphDatabase # URI = "<URI for Neo4j database>" # AUTH = ("<Username>", "<Password>") load_status = dotenv.load_dotenv("Neo4j-AURA_instanceID-created-date.txt") if load_status is False: raise RuntimeError('Environment variables not loaded.') URI = os.getenv("NEO4J_URI") AUTH = (os.getenv("NEO4J_USERNAME"), os.getenv("NEO4J_PASSWORD")) people = [{"name": "Alice", "age": 42, "friends": ["Bob", "Peter", "Anna"]}, {"name": "Bob", "age": 19}, {"name": "Peter", "age": 50}, {"name": "Anna", "age": 30}] with GraphDatabase.driver(URI, auth=AUTH) as driver: try: # Create some nodes for person in people: records, summary, keys = driver.execute_query( "MERGE (p:Person {name: $person.name, age: $person.age})", person=person, database_="neo4j", ) # Create some relationships for person in people: if person.get("friends"): records, summary, keys = driver.execute_query(""" MATCH (p:Person {name: $person.name}) UNWIND $person.friends AS friend_name MATCH (friend:Person {name: friend_name}) MERGE (p)-[:KNOWS]->(friend) """, person=person, database_="neo4j", ) # Retrieve Alice's friends who are under 40 records, summary, keys = driver.execute_query(""" MATCH (p:Person {name: $name})-[:KNOWS]-(friend:Person) WHERE friend.age < $age RETURN friend """, name="Alice", age=40, routing_="r", database_="neo4j", ) # Loop through results and do something with them for record in records: print(record) # Summary information print("The query `{query}` returned {records_count} records in {time} ms.".format( query=summary.query, records_count=len(records), time=summary.result_available_after )) except Exception as e: print(e) # further logging/processing ``` #### 範例2 Transaction 隨機產生100名員工, 及10家企業. 每家企業至多可雇用10名員工. 檢查公式如下: * Create new Person node with given name, if not exists already * Obtain most recent organization ID and the number of people linked to it * If org does not have too many employees, add this Person to that * Otherwise, create a new Organization and link Person to it * Return the Organization ID to which the new Person ends up in transaction.py ```python= import dotenv import os from neo4j import GraphDatabase load_status = dotenv.load_dotenv("Neo4j-AURA_instanceID-created-date.txt") if load_status is False: raise RuntimeError('Environment variables not loaded.') URI = os.getenv("NEO4J_URI") AUTH = (os.getenv("NEO4J_USERNAME"), os.getenv("NEO4J_PASSWORD")) employee_threshold=10 def main(): with GraphDatabase.driver(URI, auth=AUTH) as driver: with driver.session(database="neo4j") as session: for i in range(100): name = f"Thor{i}" org_id = session.execute_write(employ_person_tx, name) print(f"User {name} added to organization {org_id}") def employ_person_tx(tx, name): # Create new Person node with given name, if not exists already result = tx.run(""" MERGE (p:Person {name: $name}) RETURN p.name AS name """, name=name ) # Obtain most recent organization ID and the number of people linked to it result = tx.run(""" MATCH (o:Organization) RETURN o.id AS id, COUNT{(p:Person)-[r:WORKS_FOR]->(o)} AS employees_n ORDER BY o.created_date DESC LIMIT 1 """) org = result.single() if org is not None and org["employees_n"] == 0: raise Exception("Most recent organization is empty.") # Transaction will roll back -> not even Person is created! # If org does not have too many employees, add this Person to that if org is not None and org.get("employees_n") < employee_threshold: result = tx.run(""" MATCH (o:Organization {id: $org_id}) MATCH (p:Person {name: $name}) MERGE (p)-[r:WORKS_FOR]->(o) RETURN $org_id AS id """, org_id=org["id"], name=name ) # Otherwise, create a new Organization and link Person to it else: result = tx.run(""" MATCH (p:Person {name: $name}) CREATE (o:Organization {id: randomuuid(), created_date: datetime()}) MERGE (p)-[r:WORKS_FOR]->(o) RETURN o.id AS id """, name=name ) # Return the Organization ID to which the new Person ends up in return result.single()["id"] if __name__ == "__main__": main() ```