290 lines
7.7 KiB
Markdown
290 lines
7.7 KiB
Markdown
# Neo4j Lineage Verification Guide
|
||
|
||
Use this guide to confirm that your plants and LINEAGE relationships have been imported correctly into Neo4j. Save this file as `neo4j_lineage_check.md` for future reference.
|
||
|
||
---
|
||
|
||
## 1. Open the Neo4j Browser
|
||
|
||
1. **Ensure Neo4j is running.**
|
||
In a Docker‐Compose setup, Neo4j is typically exposed at:
|
||
|
||
```
|
||
http://localhost:7474
|
||
```
|
||
2. **Log in** with your Neo4j credentials (e.g., username `neo4j`, password as configured).
|
||
|
||
Once logged in, you can execute Cypher commands in the query pane on the left.
|
||
|
||
---
|
||
|
||
## 2. Verify That Your `Plant` Nodes Exist
|
||
|
||
Before checking relationships, confirm that nodes were created:
|
||
|
||
```cypher
|
||
MATCH (p:Plant)
|
||
RETURN p.uuid AS uuid, p.name AS common_name
|
||
LIMIT 20;
|
||
```
|
||
|
||
* This query will return up to 20 plant nodes with their `uuid` and `name` properties.
|
||
* If you see your imported plants here, it means the nodes exist in the database.
|
||
|
||
---
|
||
|
||
## 3. Check Direct Parent→Child LINEAGE Pairs
|
||
|
||
To list all direct child→parent relationships:
|
||
|
||
```cypher
|
||
MATCH (child:Plant)-[:LINEAGE]->(parent:Plant)
|
||
RETURN child.uuid AS child_uuid, parent.uuid AS parent_uuid
|
||
LIMIT 50;
|
||
```
|
||
|
||
* Each row represents one `(:Plant)-[:LINEAGE]->(:Plant)` relationship.
|
||
* `child_uuid` is the UUID of the child node, and `parent_uuid` is the UUID of its direct parent.
|
||
|
||
---
|
||
|
||
## 4. Look Up a Specific Plant by UUID or Name
|
||
|
||
If you know a particular plant’s UUID, you can confirm its properties:
|
||
|
||
```cypher
|
||
MATCH (p:Plant {uuid: "YOUR_UUID_HERE"})
|
||
RETURN p.uuid AS uuid, p.name AS common_name, p.scientific_name AS sci_name;
|
||
```
|
||
|
||
Alternatively, if you only know the common name:
|
||
|
||
```cypher
|
||
MATCH (p:Plant)
|
||
WHERE p.name = "Common Name Here"
|
||
RETURN p.uuid AS uuid, p.name AS common_name, p.scientific_name AS sci_name;
|
||
```
|
||
|
||
This helps you find the exact UUID or check that the `name` and `scientific_name` properties were stored correctly.
|
||
|
||
---
|
||
|
||
## 5. Show Children of a Given Parent
|
||
|
||
To list all direct children of a specific parent by UUID:
|
||
|
||
```cypher
|
||
MATCH (parent:Plant {uuid: "PARENT_UUID_HERE"})<-[:LINEAGE]-(child:Plant)
|
||
RETURN child.uuid AS child_uuid, child.name AS child_name;
|
||
```
|
||
|
||
* This returns every plant node that points to the specified `parent_uuid` via a `LINEAGE` relationship.
|
||
|
||
---
|
||
|
||
## 6. Visualize a Subtree Around One Node
|
||
|
||
To visualize a parent node and its children in graph form:
|
||
|
||
```cypher
|
||
MATCH subtree = (parent:Plant {uuid: "PARENT_UUID_HERE"})<-[:LINEAGE]-(child:Plant)
|
||
RETURN subtree;
|
||
```
|
||
|
||
* Switch to the “Graph” view in the Neo4j browser to see a node for the parent with arrows pointing to each child.
|
||
|
||
---
|
||
|
||
## 7. Walk the Full Ancestor Chain (Multi‐Level)
|
||
|
||
If you want to see all ancestors of a given child, use a variable‐length pattern:
|
||
|
||
```cypher
|
||
MATCH path = (desc:Plant {uuid: "CHILD_UUID_HERE"})-[:LINEAGE*1..]->(anc:Plant)
|
||
RETURN path;
|
||
```
|
||
|
||
* `[:LINEAGE*1..]` indicates “follow one or more consecutive `LINEAGE` relationships upward.”
|
||
* In “Graph” view, Neo4j will display the entire chain from child → parent → grandparent → …
|
||
|
||
To return just the list of ancestor UUIDs:
|
||
|
||
```cypher
|
||
MATCH (start:Plant {uuid: "CHILD_UUID_HERE"})-[:LINEAGE*1..]->(anc:Plant)
|
||
RETURN DISTINCT anc.uuid AS ancestor_uuid;
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Show All Descendants of a Given Parent
|
||
|
||
To find all descendants (children, grandchildren, etc.) of a root node:
|
||
|
||
```cypher
|
||
MATCH (root:Plant {uuid: "ROOT_UUID_HERE"})<-[:LINEAGE*]-(desc:Plant)
|
||
RETURN desc.uuid AS descendant_uuid, desc.name AS descendant_name;
|
||
```
|
||
|
||
* The pattern `[:LINEAGE*]` (with no lower bound specified) matches zero or more hops.
|
||
* To visualize the full descendant tree:
|
||
|
||
```cypher
|
||
MATCH subtree = (root:Plant {uuid: "ROOT_UUID_HERE"})<-[:LINEAGE*]-(desc:Plant)
|
||
RETURN subtree;
|
||
```
|
||
|
||
Then switch to “Graph” view.
|
||
|
||
---
|
||
|
||
## 9. Combining Queries for a Full Walk‐Through
|
||
|
||
1. **List a few plants** (to copy a known UUID):
|
||
|
||
```cypher
|
||
MATCH (p:Plant)
|
||
RETURN p.uuid AS uuid, p.name AS common_name
|
||
LIMIT 10;
|
||
```
|
||
2. **Pick one UUID** (e.g. `"2ee2e0e7-69de-4b8f-abfe-4ed973c3d760"`).
|
||
3. **Show its direct children**:
|
||
|
||
```cypher
|
||
MATCH (p:Plant {uuid: "2ee2e0e7-69de-4b8f-abfe-4ed973c3d760"})<-[:LINEAGE]-(child:Plant)
|
||
RETURN child.uuid AS child_uuid, child.name AS child_name;
|
||
```
|
||
4. **Show its parent** (if any):
|
||
|
||
```cypher
|
||
MATCH (p:Plant {uuid: "8b1059c8-8dd3-487a-af19-1eb548788e87"})-[:LINEAGE]->(parent:Plant)
|
||
RETURN parent.uuid AS parent_uuid, parent.name AS parent_name;
|
||
```
|
||
5. **Get the full ancestor chain** of that child:
|
||
|
||
```cypher
|
||
MATCH path = (c:Plant {uuid: "8b1059c8-8dd3-487a-af19-1eb548788e87"})-[:LINEAGE*1..]->(anc:Plant)
|
||
RETURN path;
|
||
```
|
||
6. **Get the full descendant tree** of that parent:
|
||
|
||
```cypher
|
||
MATCH subtree = (root:Plant {uuid: "2ee2e0e7-69de-4b8f-abfe-4ed973c3d760"})<-[:LINEAGE*]-(desc:Plant)
|
||
RETURN subtree;
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Checking via Python (Optional)
|
||
|
||
If you prefer to script these checks using the Neo4j Bolt driver from Python, here’s a quick example:
|
||
|
||
```python
|
||
from neo4j import GraphDatabase
|
||
|
||
uri = "bolt://localhost:7687"
|
||
auth = ("neo4j", "your_password")
|
||
driver = GraphDatabase.driver(uri, auth=auth)
|
||
|
||
def print_lineage(tx, plant_uuid):
|
||
# Show direct parent
|
||
result = tx.run(
|
||
"MATCH (c:Plant {uuid:$u})-[:LINEAGE]->(p:Plant) "
|
||
"RETURN p.uuid AS parent_uuid, p.name AS parent_name",
|
||
u=plant_uuid
|
||
)
|
||
for row in result:
|
||
print(f"Parent of {plant_uuid}: {row['parent_uuid']} ({row['parent_name']})")
|
||
|
||
# Show all ancestors
|
||
result2 = tx.run(
|
||
"MATCH path = (c:Plant {uuid:$u})-[:LINEAGE*1..]->(anc:Plant) "
|
||
"RETURN [n IN nodes(path) | n.uuid] AS all_uuids",
|
||
u=plant_uuid
|
||
)
|
||
for row in result2:
|
||
print("Ancestor chain UUIDs:", row["all_uuids"])
|
||
|
||
with driver.session() as session:
|
||
session.read_transaction(print_lineage, "8b1059c8-8dd3-487a-af19-1eb548788e87")
|
||
|
||
driver.close()
|
||
```
|
||
|
||
* Install `neo4j` Python package if needed:
|
||
|
||
```bash
|
||
pip install neo4j
|
||
```
|
||
* Adjust the `uri` and `auth` values to match your Neo4j setup.
|
||
|
||
---
|
||
|
||
## 11. Summary of Key Cypher Queries
|
||
|
||
* **List all plants (sample):**
|
||
|
||
```cypher
|
||
MATCH (p:Plant)
|
||
RETURN p.uuid AS uuid, p.name AS common_name
|
||
LIMIT 20;
|
||
```
|
||
|
||
* **List direct parent→child relationships:**
|
||
|
||
```cypher
|
||
MATCH (child:Plant)-[:LINEAGE]->(parent:Plant)
|
||
RETURN child.uuid AS child_uuid, parent.uuid AS parent_uuid;
|
||
```
|
||
|
||
* **List direct children of a parent:**
|
||
|
||
```cypher
|
||
MATCH (parent:Plant {uuid:"PARENT_UUID"})<-[:LINEAGE]-(child:Plant)
|
||
RETURN child.uuid AS child_uuid, child.name AS child_name;
|
||
```
|
||
|
||
* **List direct parent of a child:**
|
||
|
||
```cypher
|
||
MATCH (child:Plant {uuid:"CHILD_UUID"})-[:LINEAGE]->(parent:Plant)
|
||
RETURN parent.uuid AS parent_uuid, parent.name AS parent_name;
|
||
```
|
||
|
||
* **Visualize parent + children subgraph:**
|
||
|
||
```cypher
|
||
MATCH subtree = (parent:Plant {uuid:"PARENT_UUID"})<-[:LINEAGE]-(child:Plant)
|
||
RETURN subtree;
|
||
```
|
||
|
||
* **Full ancestor chain for a child:**
|
||
|
||
```cypher
|
||
MATCH path = (c:Plant {uuid:"CHILD_UUID"})-[:LINEAGE*1..]->(anc:Plant)
|
||
RETURN path;
|
||
```
|
||
|
||
* **Full descendant tree for a parent:**
|
||
|
||
```cypher
|
||
MATCH subtree = (root:Plant {uuid:"PARENT_UUID"})<-[:LINEAGE*]-(desc:Plant)
|
||
RETURN subtree;
|
||
```
|
||
|
||
---
|
||
|
||
### Usage Tips
|
||
|
||
* **Switch between “Table” and “Graph” views** in the Neo4j Browser to see raw data vs. visual graph.
|
||
* Use `LIMIT` when you only want a quick preview of results.
|
||
* To filter by partial names, you can do:
|
||
|
||
```cypher
|
||
MATCH (p:Plant)
|
||
WHERE toLower(p.name) CONTAINS toLower("baltic")
|
||
RETURN p.uuid, p.name;
|
||
```
|
||
* Remember to enclose string literals in double quotes (`"..."`) and escape any internal quotes if needed.
|
||
|
||
Keep this guide handy for whenever you need to verify or debug your Neo4j lineage data!
|