# 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!