# 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()
```