Cypher 指南

MATCH 与 RETURN

MATCH 在图中查找模式,节点使用 (),关系使用 []。

// Find all nodes with label Person
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.age DESC
LIMIT 10;

// Find node by property
MATCH (p:Person {name: "Alice"})
RETURN p;

// Traverse a relationship
MATCH (a:Person)-[:KNOWS]->(b:Person)
RETURN a.name, b.name;

// Directed vs undirected
MATCH (a)-[:KNOWS]->(b)   // directed: a knows b
MATCH (a)-[:KNOWS]-(b)    // undirected: either direction

// Variable-length path (1 to 3 hops)
MATCH (a:Person {name:"Alice"})-[:KNOWS*1..3]->(b:Person)
RETURN DISTINCT b.name;

// WHERE clause
MATCH (p:Person)
WHERE p.age >= 18 AND p.country = "US"
RETURN p.name;

// Optional match (like LEFT JOIN)
MATCH (p:Person {name:"Alice"})
OPTIONAL MATCH (p)-[:HAS_PET]->(pet)
RETURN p.name, pet.name;

CREATE 与 MERGE

// CREATE node
CREATE (p:Person {name: "Bob", age: 30, email: "bob@example.com"});

// CREATE relationship
MATCH (a:Person {name:"Alice"}), (b:Person {name:"Bob"})
CREATE (a)-[:KNOWS {since: 2020}]->(b);

// CREATE with RETURN
CREATE (p:Product {id: 1, name: "Laptop", price: 999})
RETURN p;

// MERGE: create only if not exists (get or create)
MERGE (p:Person {email: "carol@example.com"})
ON CREATE SET p.name = "Carol", p.createdAt = datetime()
ON MATCH  SET p.lastSeen = datetime()
RETURN p;

// MERGE relationship
MATCH (a:Person {name:"Alice"}), (b:Person {name:"Bob"})
MERGE (a)-[:FOLLOWS]->(b);

// SET: update properties
MATCH (p:Person {name:"Alice"})
SET p.age = 31, p.active = true;

// REMOVE: delete property or label
MATCH (p:Person {name:"Alice"})
REMOVE p.active;

// DELETE node (must have no relationships first)
MATCH (p:Person {name:"Temp"})
DETACH DELETE p;   -- DETACH removes relationships too

聚合与 WITH

// count, collect, sum, avg
MATCH (p:Person)-[:KNOWS]->(friend)
RETURN p.name, count(friend) AS friend_count
ORDER BY friend_count DESC;

// collect: aggregate into list
MATCH (p:Person)-[:LIKES]->(m:Movie)
RETURN p.name, collect(m.title) AS liked_movies;

// WITH: intermediate results (like a subquery)
MATCH (p:Person)-[:KNOWS]->(friend)
WITH p, count(friend) AS cnt
WHERE cnt > 3
RETURN p.name, cnt;

// UNWIND: expand a list into rows
UNWIND [1, 2, 3] AS x
RETURN x * 2;

// UNWIND with MERGE (bulk insert from list)
UNWIND [{name:"A",age:25},{name:"B",age:30}] AS row
MERGE (p:Person {name: row.name})
SET p.age = row.age;

索引与约束

-- Create index (Neo4j 4.x+)
CREATE INDEX idx_person_name FOR (p:Person) ON (p.name);
CREATE INDEX idx_person_email FOR (p:Person) ON (p.email);

-- Composite index
CREATE INDEX idx_product_cat_price FOR (p:Product) ON (p.category, p.price);

-- Full-text index
CREATE FULLTEXT INDEX idx_article_body FOR (a:Article) ON EACH [a.title, a.body];
CALL db.index.fulltext.queryNodes("idx_article_body", "neo4j performance") YIELD node, score;

-- Unique constraint (implies index)
CREATE CONSTRAINT uq_person_email FOR (p:Person) REQUIRE p.email IS UNIQUE;

-- Existence constraint (Enterprise)
CREATE CONSTRAINT nn_person_name FOR (p:Person) REQUIRE p.name IS NOT NULL;

-- List indexes
SHOW INDEXES;
SHOW CONSTRAINTS;

APOC 过程

-- APOC (Awesome Procedures on Cypher) must be installed

-- Load JSON from URL
CALL apoc.load.json("https://api.example.com/data") YIELD value
UNWIND value.items AS item
MERGE (p:Product {id: item.id}) SET p.name = item.name;

-- Batch execution (avoid heap overflow on large imports)
CALL apoc.periodic.iterate(
  "MATCH (p:Person) RETURN p",
  "SET p.processed = true",
  {batchSize: 1000, parallel: false}
);

-- Date formatting
RETURN apoc.date.format(timestamp(), 'ms', 'yyyy-MM-dd');

-- String utilities
RETURN apoc.text.camelCase("hello world");
RETURN apoc.text.slugify("Hello World!");

-- Graph algorithms (via GDS or APOC)
CALL apoc.algo.dijkstra(startNode, endNode, 'ROAD', 'distance')
YIELD path, weight;