Cypher Query Tutorial: MATCH, CREATE, MERGE, and Graph Traversal for GraphRAG Applications
TL;DR — Cypher query tutorial: MATCH, CREATE, MERGE, traversal, vector search. Neo4j Cypher Manual: "Cypher is Neo4j declarative query language for expressive and efficient querying of property graphs." Core Concepts: "Quantified relationships find paths up to N hops. DISTINCT for unique results. Fixed {n}, range 1..3, any ." Basic Queries: "Fixed length with quantifier {n}, variable length with *1..3, shortest path with shortestPath()." GraphRAG Python: "HybridCypherRetriever: vector + fulltext index, retrieval query traverses graph for more context." Cypher Decoded: "MATCH, WHERE, RETURN, CREATE, MERGE, SET — core knowledge for Neo4j queries." Learn more with knowledge graph basics, build from documents, FalkorDB vs Neo4j, and GraphRAG tutorial.
Neo4j Cypher Manual introduces the language: "Cypher is Neo4j's declarative query language, allowing expressive and efficient querying of property graphs."
Cypher Decoded adds: "From fundamental Cypher keywords like MATCH, WHERE, and RETURN to powerful data manipulation clauses like CREATE, MERGE, and SET — you're now equipped with the core knowledge to start crafting your own Neo4j queries."
Cypher Query Architecture
MATCH: find patterns
WHERE: filter
RETURN: output
WITH: chain parts
UNION: combine
UNWIND: expand lists"] Writing["Writing
CREATE: new nodes/edges
MERGE: upsert (idempotent)
SET: update properties
DELETE: remove
REMOVE: remove properties
FOREACH: batch ops"] end subgraph Patterns["Pattern Matching"] Node["Node Pattern
(n:Label {prop:value})
variables, labels, props"] Rel["Relationship Pattern
-[r:TYPE]->
direction, type, props"] Path["Path Pattern
(a)-[:KNOWS*2]->(b)
fixed length: {n}
range: *1..3
any: *"] end subgraph Traversal["Graph Traversal"] Fixed["Fixed Hop
-[:TYPE*2]->
exactly n hops"] Range["Range Hop
-[:TYPE*1..3]->
1 to 3 hops"] Any["Any Hop
-[:TYPE*]->
any distance"] Shortest["Shortest Path
shortestPath()
allShortestPaths()
between two nodes"] end subgraph Vector["Vector Search (GraphRAG)"] Index["Vector Index
CREATE INDEX FOR (n:Chunk)
ON (n.embedding)
vector index type"] Query["Vector Query
CALL db.index.vector
.queryNodes(index, k, $vec)
YIELD node, score"] Expand["Graph Expansion
MATCH (node)-[:MENTIONS]->(e)
MATCH (e)<-[:MENTIONS]-(c2)
return more context"] Hybrid["Hybrid Retrieval
vector + fulltext + graph
HybridCypherRetriever
GraphRAG pipeline"] end subgraph Python["Python Integration"] Driver["Neo4j Driver
from neo4j import GraphDatabase
driver.session()
session.run(query, params)"] Falkor["FalkorDB
from falkordb import FalkorDB
graph.query(cypher)
OpenCypher compatible"] Lang["LangChain
Neo4jGraph.query()
GraphCypherQAChain
NL to Cypher"] Llama["LlamaIndex
Neo4jPropertyGraphStore
CypherTemplateRetriever
VectorContextRetriever"] end Reading --> Node Writing --> Rel Node --> Path Rel --> Path Path --> Fixed Path --> Range Path --> Any Path --> Shortest Index --> Query Query --> Expand Expand --> Hybrid Driver --> Lang Falkor --> Llama style Clauses fill:#4169E1,color:#fff style Patterns fill:#39FF14,color:#000 style Traversal fill:#2D1B69,color:#fff style Vector fill:#FF6B6B,color:#fff
Cypher Clause Reference
| Clause | Purpose | Example | Use Case |
|---|---|---|---|
| MATCH | Find patterns | MATCH (p:Person)-[:WORKS_AT]->(o) |
Query existing data |
| WHERE | Filter results | WHERE p.age > 30 AND o.name = 'AI Lab' |
Conditional filtering |
| RETURN | Specify output | RETURN p.name, o.name |
Query results |
| CREATE | Create nodes/edges | CREATE (p:Person {name:'Alice'}) |
Add new data |
| MERGE | Upsert (idempotent) | MERGE (p:Person {name:$name}) SET p.age=$age |
Ingestion without duplicates |
| SET | Update properties | SET p.updated = timestamp() |
Modify existing data |
| DELETE | Remove nodes/edges | MATCH (n) DETACH DELETE n |
Remove data |
| ORDER BY | Sort results | ORDER BY p.name DESC |
Sorting |
| LIMIT | Restrict count | LIMIT 10 |
Pagination |
| WITH | Chain query parts | WITH p, count(o) as orgs |
Multi-step queries |
| UNWIND | Expand lists | UNWIND $names AS name |
Batch operations |
| FOREACH | Batch operations | FOREACH (n IN nodes \| MERGE (n)) |
Bulk updates |
Implementation
from dataclasses import dataclass
from typing import Optional
from enum import Enum
class QueryType(Enum):
READ = "read"
WRITE = "write"
TRAVERSAL = "traversal"
VECTOR = "vector"
@dataclass
class CypherQueryGuide:
"""Cypher query tutorial implementation guide."""
def get_basic_queries(self) -> str:
"""Basic Cypher queries."""
return (
"// === BASIC CYPHER QUERIES ===\n"
"\n"
"// CREATE nodes\n"
"CREATE (p:Person {\n"
" name: 'Dr. Smith',\n"
" role: 'Researcher'\n"
"})\n"
"CREATE (o:Organization {\n"
" name: 'AI Lab',\n"
" type: 'research'\n"
"})\n"
"\n"
"// CREATE relationships\n"
"MATCH (p:Person {name:'Dr. Smith'}),\n"
" (o:Organization {name:'AI Lab'})\n"
"CREATE (p)-[:WORKS_AT {since: 2020}]->(o)\n"
"\n"
"// MERGE (idempotent upsert)\n"
"MERGE (p:Person {name: $name})\n"
" ON CREATE SET p.created = timestamp()\n"
" ON MATCH SET p.updated = timestamp()\n"
"SET p.role = $role\n"
"\n"
"// MATCH with WHERE\n"
"MATCH (p:Person)-[:WORKS_AT]->(o:Organization)\n"
"WHERE o.name = 'AI Lab'\n"
" AND p.role = 'Researcher'\n"
"RETURN p.name, p.role, o.name\n"
"ORDER BY p.name\n"
"LIMIT 10\n"
"\n"
"// WITH chaining\n"
"MATCH (p:Person)-[:WORKS_AT]->(o)\n"
"WITH o, count(p) as employee_count\n"
"WHERE employee_count > 5\n"
"RETURN o.name, employee_count\n"
"ORDER BY employee_count DESC\n"
"\n"
"// UNWIND for batch\n"
"UNWIND $people AS person\n"
"MERGE (p:Person {name: person.name})\n"
"SET p.role = person.role"
)
def get_traversal_queries(self) -> str:
"""Multi-hop traversal queries."""
return (
"// === GRAPH TRAVERSAL ===\n"
"\n"
"// Fixed length: exactly 2 hops\n"
"MATCH (p:Person)-[:KNOWS*2]->(friend)\n"
"RETURN p.name, friend.name\n"
"\n"
"// Range: 1 to 3 hops\n"
"MATCH (p:Person)-[:KNOWS*1..3]->(contact)\n"
"WHERE contact.name <> p.name\n"
"RETURN DISTINCT p.name, contact.name\n"
"\n"
"// Any distance\n"
"MATCH (p:Person {name:'Alice'})\n"
" -[:KNOWS*]->(contact)\n"
"RETURN DISTINCT contact.name\n"
"LIMIT 50\n"
"\n"
"// Quantified relationship\n"
"// up to 5 hops, type KNOWS\n"
"MATCH (a:Person {name:'Anna'})\n"
" -[:KNOWS*1..5]->(p:Person)\n"
"WHERE p.age < a.age\n"
"RETURN DISTINCT p.name\n"
"\n"
"// Shortest path\n"
"MATCH (a:Person {name:'Alice'}),\n"
" (b:Person {name:'Bob'}),\n"
" p = shortestPath(\n"
" (a)-[:KNOWS*]-(b))\n"
"RETURN p\n"
"\n"
"// All shortest paths\n"
"MATCH (a:Person {name:'Alice'}),\n"
" (b:Person {name:'Bob'}),\n"
" p = allShortestPaths(\n"
" (a)-[:KNOWS*]-(b))\n"
"RETURN p\n"
"\n"
"// Multi-hop with filtering\n"
"MATCH path = (p:Person)\n"
" -[:WORKS_AT]->(o:Organization)\n"
" -[:PARTNER_OF]->(o2:Organization)\n"
"WHERE o.name = 'AI Lab'\n"
"RETURN p.name, o.name, o2.name\n"
"\n"
"// Path with relationships\n"
"MATCH p = (a)-[:KNOWS*1..3]->(b)\n"
"RETURN relationships(p) AS rels,\n"
" nodes(p) AS nodes"
)
def get_vector_search(self) -> str:
"""Vector search for GraphRAG."""
return (
"// === VECTOR SEARCH (GraphRAG) ===\n"
"\n"
"// Create vector index\n"
"CREATE VECTOR INDEX chunk_embeddings\n"
"FOR (c:Chunk) ON (c.embedding)\n"
"OPTIONS {\n"
" indexConfig: {\n"
" `vector.dimensions`: 384,\n"
" `vector.similarity_function`:\n"
" 'cosine'\n"
" }\n"
"}\n"
"\n"
"// Vector similarity search\n"
"CALL db.index.vector.queryNodes(\n"
" 'chunk_embeddings',\n"
" 5, // top k\n"
" $query_vector\n"
")\n"
"YIELD node, score\n"
"RETURN node.text AS text, score\n"
"ORDER BY score DESC\n"
"\n"
"// GraphRAG: vector + graph expansion\n"
"CALL db.index.vector.queryNodes(\n"
" 'chunk_embeddings',\n"
" 5, $query_vector\n"
")\n"
"YIELD node AS seed, score\n"
"MATCH (seed)-[:MENTIONS]->(e)\n"
"MATCH (e)<-[:MENTIONS]-(c2:Chunk)\n"
"RETURN DISTINCT\n"
" c2.text AS context,\n"
" collect(e.name) AS entities,\n"
" score\n"
"LIMIT 20\n"
"\n"
"// Hybrid: vector + fulltext\n"
"CALL {\n"
" CALL db.index.vector.queryNodes(\n"
" 'chunk_embeddings',\n"
" 5, $query_vector\n"
" ) YIELD node, score\n"
" RETURN node, score\n"
" UNION\n"
" CALL db.index.fulltext.queryNodes(\n"
" 'chunk_text',\n"
" $query_text\n"
" ) YIELD node, score\n"
" RETURN node, score\n"
"}\n"
"WITH node, collect(score) AS scores\n"
"MATCH (node)-[:MENTIONS]->(e)\n"
"RETURN node.text, e.name,\n"
" max(scores) AS best_score"
)
def get_python_integration(self) -> str:
"""Python neo4j driver integration."""
return (
"# === PYTHON INTEGRATION ===\n"
"from neo4j import GraphDatabase\n"
"\n"
"driver = GraphDatabase.driver(\n"
" 'bolt://localhost:7687',\n"
" auth=('neo4j', 'password'))\n"
"\n"
"# 1. Simple query\n"
"with driver.session() as sess:\n"
" result = sess.run(\n"
" '''MATCH (p:Person)\n"
" -[:WORKS_AT]->(o)\n"
" WHERE o.name = $org\n"
" RETURN p.name''',\n"
" org='AI Lab')\n"
" for record in result:\n"
" print(record['p.name'])\n"
"\n"
"# 2. Parameterized MERGE\n"
"with driver.session() as sess:\n"
" sess.run(\n"
" '''MERGE (p:Person\n"
" {name: $name})\n"
" SET p.role = $role''',\n"
" name='Dr. Smith',\n"
" role='Researcher')\n"
"\n"
"# 3. Transaction (write)\n"
"def add_person(tx, name, role):\n"
" tx.run(\n"
" '''MERGE (p:Person\n"
" {name: $name})\n"
" SET p.role = $role''',\n"
" name=name, role=role)\n"
"\n"
"with driver.session() as sess:\n"
" sess.execute_write(\n"
" add_person,\n"
" 'Alice', 'Engineer')\n"
"\n"
"# 4. Batch with UNWIND\n"
"with driver.session() as sess:\n"
" sess.run(\n"
" '''UNWIND $people AS person\n"
" MERGE (p:Person\n"
" {name: person.name})\n"
" SET p.role = person.role''',\n"
" people=[\n"
" {'name':'Alice',\n"
" 'role':'Engineer'},\n"
" {'name':'Bob',\n"
" 'role':'Designer'},\n"
" ])\n"
"\n"
"# 5. FalkorDB (OpenCypher)\n"
"from falkordb import FalkorDB\n"
"db = FalkorDB(\n"
" host='localhost', port=6379)\n"
"graph = db.select_graph('mygraph')\n"
"result = graph.query(\n"
" '''MATCH (p:Person)\n"
" -[:WORKS_AT]->(o)\n"
" RETURN p.name, o.name''')\n"
"for row in result.result_set:\n"
" print(row)\n"
"\n"
"driver.close()"
)
def get_graphrag_queries(self) -> str:
"""GraphRAG-specific Cypher queries."""
return (
"// === GRAPHRAG CYPHER ===\n"
"\n"
"// Schema: Document→Chunk→Entity\n"
"// Find entities mentioned in chunks\n"
"MATCH (d:Document)\n"
" -[:CONTAINS]->(c:Chunk)\n"
" -[:MENTIONS]->(e)\n"
"WHERE d.id = $doc_id\n"
"RETURN e.name, e.type,\n"
" count(c) AS mentions\n"
"ORDER BY mentions DESC\n"
"\n"
"// Multi-hop: person → org → partners\n"
"MATCH (p:Person)\n"
" -[:WORKS_AT]->(o:Organization)\n"
" -[:PARTNER_OF]->(o2:Organization)\n"
"RETURN p.name, o.name, o2.name\n"
"\n"
"// Community detection results\n"
"MATCH (c:Community)\n"
" -[:HAS_MEMBER]->(e:Entity)\n"
"WHERE c.level = 2\n"
"RETURN c.name AS community,\n"
" collect(e.name) AS members\n"
"\n"
">// Temporal query (Graphiti-style)\n"
"MATCH (p:Person {name:'Alice'})\n"
" -[r:WORKS_AT]->(o)\n"
"WHERE r.valid_at <= $point_in_time\n"
" AND (r.invalid_at IS NULL\n"
" OR r.invalid_at > $point_in_time)\n"
"RETURN o.name AS employer_at_time\n"
"\n"
"// Provenance: trace fact to source\n"
"MATCH (e:Entity {name:'Dr. Smith'})\n"
" <-[:MENTIONS]-(c:Chunk)\n"
" <-[:CONTAINS]-(d:Document)\n"
"RETURN d.title, d.url, c.text\n"
"\n"
"// Aggregation: entity co-occurrence\n"
"MATCH (c:Chunk)\n"
" -[:MENTIONS]->(e1:Entity),\n"
" (c)-[:MENTIONS]->(e2:Entity)\n"
"WHERE e1.name < e2.name\n"
"RETURN e1.name, e2.name,\n"
" count(c) AS co_occurrences\n"
"ORDER BY co_occurrences DESC\n"
"LIMIT 20"
)
def get_clause_reference(self) -> dict:
"""Cypher clause reference."""
return {
"MATCH": "Find patterns in graph — nodes and relationships matching specified labels and properties",
"WHERE": "Filter results by conditions — supports AND, OR, NOT, IN, EXISTS, string matching",
"RETURN": "Specify what to return — nodes, relationships, properties, aggregations",
"CREATE": "Create new nodes and relationships — fails if already exists (use MERGE for upsert)",
"MERGE": "Create if not exists, match if exists — idempotent upsert, use ON CREATE SET / ON MATCH SET",
"SET": "Update properties on nodes and relationships — can set multiple properties at once",
"DELETE": "Remove nodes or relationships — DETACH DELETE removes node and all its relationships",
"ORDER_BY": "Sort results by property — ASC (default) or DESC",
"LIMIT": "Restrict number of returned results — often combined with ORDER BY",
"WITH": "Chain query parts — pipes output of one part as input to next, like Unix pipe",
"UNION": "Combine results from multiple queries — must have same column names",
"UNWIND": "Expand list into individual rows — useful for batch operations",
"FOREACH": "Execute operations for each item in list — used for bulk updates",
"CALL": "Call stored procedures — db.index.vector.queryNodes, db.index.fulltext.queryNodes",
}
Cypher Query Checklist
- [ ] Cypher: Neo4j declarative query language for property graphs — expressive and efficient
- [ ] MATCH: find patterns in graph (nodes and relationships matching labels/properties)
- [ ] WHERE: filter results by conditions (AND, OR, NOT, IN, EXISTS, string matching)
- [ ] RETURN: specify output — nodes, relationships, properties, aggregations
- [ ] CREATE: create new nodes and relationships — use for initial data, not ingestion
- [ ] MERGE: idempotent upsert — create if not exists, match if exists
- [ ] MERGE: ON CREATE SET / ON MATCH SET for conditional property updates
- [ ] MERGE: always use for ingestion to avoid duplicates (not CREATE)
- [ ] MERGE: use unique constraints for performance (MERGE locks the node)
- [ ] SET: update properties on nodes and relationships
- [ ] DELETE: remove nodes or relationships — DETACH DELETE removes node + all relationships
- [ ] ORDER BY: sort results — ASC (default) or DESC
- [ ] LIMIT: restrict number of results — combine with ORDER BY for top-k
- [ ] WITH: chain query parts — pipes output as input to next part
- [ ] UNION: combine results from multiple queries — same column names required
- [ ] UNWIND: expand list into individual rows — batch operations
- [ ] FOREACH: execute operations for each item in list — bulk updates
- [ ] CALL: call stored procedures — db.index.vector.queryNodes, db.index.fulltext.queryNodes
- [ ] Node pattern: (variable:Label {prop: value}) — variables, labels, properties
- [ ] Relationship pattern: -[variable:TYPE {prop: value}]-> — direction, type, properties
- [ ] Fixed-length traversal: -[:TYPE*2]-> exactly n hops
- [ ] Range traversal: -[:TYPE*1..3]-> 1 to 3 hops
- [ ] Any-distance traversal: -[:TYPE*]-> any number of hops
- [ ] Quantified relationship: -[:KNOWS*1..5]-> with WHERE filtering during traversal
- [ ] Shortest path: shortestPath((a)-[:TYPE*]-(b)) — single shortest path
- [ ] All shortest paths: allShortestPaths((a)-[:TYPE*]-(b)) — all shortest paths
- [ ] DISTINCT: ensure unique results in RETURN
- [ ] relationships(p): get relationships from a path
- [ ] nodes(p): get nodes from a path
- [ ] Vector index: CREATE VECTOR INDEX ... FOR (n:Label) ON (n.embedding) with dimensions and similarity function
- [ ] Vector query: CALL db.index.vector.queryNodes('index', k, $vector) YIELD node, score
- [ ] GraphRAG retrieval: vector seeds → graph expansion via MENTIONS → return context + entities + scores
- [ ] Hybrid retrieval: vector + fulltext via UNION CALL — combine semantic and keyword matching
- [ ] HybridCypherRetriever: vector + fulltext index, retrieval query traverses graph for more context
- [ ] Schema queries: Document→Chunk→Entity with CONTAINS and MENTIONS relationships
- [ ] Multi-hop: Person→Organization→Partner for multi-hop reasoning
- [ ] Community: Community→HAS_MEMBER→Entity for community-level queries
- [ ] Temporal: WHERE r.valid_at <= $time AND (r.invalid_at IS NULL OR r.invalid_at > $time)
- [ ] Provenance: trace Entity←MENTIONS←Chunk←CONTAINS←Document to source
- [ ] Co-occurrence: count chunks mentioning both entities for entity co-occurrence analysis
- [ ] Python: from neo4j import GraphDatabase, driver.session(), session.run(query, params)
- [ ] Python: session.execute_write(tx_func) for transactional writes
- [ ] Python: parameterized queries with $param syntax for safety
- [ ] Python: batch with UNWIND $list AS item
- [ ] FalkorDB: from falkordb import FalkorDB, graph.query(cypher) — OpenCypher compatible
- [ ] LangChain: Neo4jGraph.query(), GraphCypherQAChain for NL to Cypher
- [ ] LlamaIndex: Neo4jPropertyGraphStore, CypherTemplateRetriever, VectorContextRetriever
- [ ] Always close driver: driver.close()
- [ ] Read knowledge graph basics for concepts
- [ ] Read build from documents for ingestion
- [ ] Read FalkorDB vs Neo4j for database comparison
- [ ] Read GraphRAG tutorial for GraphRAG queries
- [ ] Test: MATCH returns expected nodes and relationships
- [ ] Test: MERGE is idempotent — re-running doesn't create duplicates
- [ ] Test: multi-hop traversal returns correct paths
- [ ] Test: vector search returns relevant results with scores
- [ ] Test: hybrid retrieval combines vector + fulltext effectively
- [ ] Test: parameterized queries prevent injection
- [ ] Test: batch UNWIND performance for bulk operations
- [ ] Document query patterns, indexes, traversal strategies, GraphRAG retrieval approach
FAQ
What are the basic Cypher query clauses?
MATCH, WHERE, RETURN, CREATE, MERGE, SET, DELETE, ORDER BY, LIMIT. Neo4j Cypher Manual: "Cypher is Neo4j declarative query language, allowing expressive and efficient querying of property graphs." Cypher Decoded: "From fundamental Cypher keywords like MATCH, WHERE, and RETURN to powerful data manipulation clauses like CREATE, MERGE, and SET — core knowledge to start crafting Neo4j queries." Basic clauses: (1) MATCH: find patterns in graph (nodes and relationships). (2) WHERE: filter results by conditions. (3) RETURN: specify what to return. (4) CREATE: create nodes and relationships. (5) MERGE: create if not exists (idempotent upsert). (6) SET: update properties on nodes/edges. (7) DELETE: remove nodes or relationships. (8) ORDER BY: sort results. (9) LIMIT: restrict number of results. (10) WITH: chain query parts.
How do you write multi-hop traversal queries in Cypher?
Use variable-length path patterns with quantifiers for multi-hop traversal. Cypher Manual - Core Concepts: "Quantified relationship finds all paths up to 5 hops away, traversing only relationships of type KNOWS. DISTINCT operator ensures RETURN clause only returns unique nodes." Cypher Manual - Basic Queries: "Several ways to search for paths between nodes. Fixed length: specify distance with quantifier {n}. MATCH (p:Person)-[:KNOWS2]->(friend) matches exactly 2 hops. Variable length: -[:KNOWS1..3]-> for 1 to 3 hops. -[:KNOWS]-> for any number of hops." Multi-hop: (1) Fixed: -[:TYPE2]-> exactly 2 hops. (2) Range: -[:TYPE1..3]-> 1 to 3 hops. (3) Any: -[:TYPE]-> any distance. (4) Shortest path: shortestPath((a)-[:TYPE*]-(b)). (5) All paths: allShortestPaths. (6) Filter with WHERE during traversal.
How do you use vector search in Cypher for GraphRAG?
Use db.index.vector.queryNodes for semantic retrieval, then expand with graph traversal. Neo4j GraphRAG Python: "Hybrid Cypher Retriever: results searched in both vector and full-text index. Once similar nodes identified, retrieval query traverses graph and returns more context. HybridCypherRetriever with INDEX_NAME, FULLTEXT_INDEX_NAME, retrieval query." Vector search: (1) Create vector index: CREATE INDEX ... FOR (n:Chunk) ON (n.embedding). (2) Query: CALL db.index.vector.queryNodes('index', k, $vector) YIELD node, score. (3) Expand: MATCH (node)-[:MENTIONS]->(e) MATCH (e)<-[:MENTIONS]-(c2:Chunk). (4) Hybrid: vector + fulltext + graph traversal. (5) Return: chunks + entities + scores. (6) GraphRAG: semantic seeds → graph expansion → re-rank → answer.
How do you use MERGE for idempotent upserts in Cypher?
MERGE creates a node/relationship if it doesn't exist, or matches if it does — idempotent. MERGE: (1) MERGE (n:Person {name: $name}) — creates or matches. (2) SET n.age = $age — updates properties on match or create. (3) MERGE with ON CREATE SET / ON MATCH SET for conditional properties. (4) MERGE (a)-[:KNOWS]->(b) — creates relationship if not exists. (5) MATCH + MERGE for relationships between existing nodes. (6) Always use MERGE (not CREATE) for ingestion to avoid duplicates. (7) MERGE locks the node — use unique constraints for performance. (8) Pattern: MERGE (d:Document {id:$id}) SET d.title=$title. (9) MERGE (c:Chunk {id:$cid}) SET c.text=$text. (10) MATCH (d),(c) MERGE (d)-[:CONTAINS]->(c).
How do you run Cypher queries from Python?
Use neo4j Python driver with session.run or execute_write for transactions. Python: (1) from neo4j import GraphDatabase. (2) driver = GraphDatabase.driver('bolt://localhost:7687', auth=('neo4j','password')). (3) with driver.session() as session: session.run('MATCH (n) RETURN n'). (4) Parameterized: session.run('MATCH (p:Person {name:$name}) RETURN p', name='Alice'). (5) Transactions: session.execute_write(tx_func). (6) Results: for record in result: record['p.name']. (7) FalkorDB: from falkordb import FalkorDB, graph.query('Cypher'). (8) LangChain: Neo4jGraph.query() or GraphCypherQAChain. (9) LlamaIndex: Neo4jPropertyGraphStore. (10) Always close driver: driver.close().
Want a self-hosted AI company brain that does all of this out of the box?
Book a demo →