PART 1 · Neo4j & Cypher

Cypher 고급 문법

가변 길이 경로, 최단 경로, 집계 함수, WITH, UNWIND 등 실전에서 자주 쓰이는 고급 패턴을 다룹니다.

1. 가변 길이 경로 탐색

기본 문법에서는 (a)-[:KNOWS]->(b)처럼 1단계 관계만 탐색했습니다.
하지만 실전에서는 "친구의 친구의 친구"처럼 여러 단계를 탐색해야 할 때가 많습니다.

A
B
C
D
E
가변 길이 경로 문법
// 1~3단계 KNOWS 관계 탐색
MATCH (a:Person {name: "A"})-[:KNOWS*1..3]->(friend)
RETURN friend.name

*의 다양한 표기법

*1..3 → 1단계 이상, 3단계 이하
*2 → 정확히 2단계
*..5 → 최대 5단계까지 (1~5)
*3.. → 최소 3단계 이상
* → 모든 단계 (주의: 성능 이슈 가능)

성능 주의

*만 쓰면 그래프 전체를 탐색할 수 있어 매우 느려질 수 있습니다.
반드시 상한을 지정하세요: *1..5 등.
실무에서는 보통 3~5단계 이내를 사용합니다.

2. 최단 경로

두 노드 사이의 가장 짧은 경로를 찾는 함수입니다.
소셜 네트워크에서 "A와 E가 몇 다리 건너 아는 사이인가?"를 알 수 있습니다.

shortestPath
MATCH path = shortestPath(
    (a:Person {name: "A"})-[*..10]->(e:Person {name: "E"})
)
RETURN path, length(path) AS 거리
allShortestPaths — 같은 길이의 모든 최단 경로
MATCH path = allShortestPaths(
    (a:Person {name: "A"})-[*..10]->(e:Person {name: "E"})
)
RETURN path

경로(path)에서 정보 추출

length(path) → 경로의 관계 수 (거리)
nodes(path) → 경로에 포함된 노드 목록
relationships(path) → 경로에 포함된 관계 목록

shortestPath에도 상한이 필요합니다.

[*..10]처럼 최대 탐색 깊이를 지정하세요.
상한 없이 쓰면 전체 그래프를 탐색하게 됩니다.

3. 집계 함수

SQL의 GROUP BY + 집계 함수와 비슷한 기능입니다.
Cypher에서는 RETURN에서 집계 함수를 쓰면 자동으로 그룹화됩니다.

주요 집계 함수
// 전체 Person 수
MATCH (p:Person)
RETURN count(p) AS 인원수

// 장르별 영화 수
MATCH (m:Movie)
RETURN m.genre, count(m) AS 영화수
ORDER BY 영화수 DESC

// 평균 평점
MATCH (:Person)-[r:WATCHED]->(:Movie)
RETURN avg(r.rating) AS 평균평점
함수 설명 예시
count() 개수 count(n)
sum() 합계 sum(r.amount)
avg() 평균 avg(r.rating)
min() / max() 최솟값 / 최댓값 min(n.age)
collect() 결과를 리스트로 모음 collect(m.title)

collect()는 Cypher만의 강력한 함수입니다.

여러 행의 결과를 하나의 리스트로 묶어줍니다.

MATCH (p:Person)-[:WATCHED]->(m:Movie)
RETURN p.name, collect(m.title) AS 본영화목록

결과: 홍길동 | ["인셉션", "매트릭스", "인터스텔라"]

4. WITH — 중간 결과 전달

WITH는 쿼리를 여러 단계로 나누는 파이프라인입니다.
앞 단계의 결과를 다음 단계로 전달하며, 중간에 필터링·정렬·집계를 할 수 있습니다.

영화를 3편 이상 본 사람만 조회
MATCH (p:Person)-[:WATCHED]->(m:Movie)
WITH p, count(m) AS movieCount
WHERE movieCount >= 3
RETURN p.name, movieCount
ORDER BY movieCount DESC
상위 5명의 시청 영화 목록
MATCH (p:Person)-[:WATCHED]->(m:Movie)
WITH p, count(m) AS cnt
ORDER BY cnt DESC
LIMIT 5
// 상위 5명에 대해 다시 영화 목록 조회
MATCH (p)-[:WATCHED]->(m:Movie)
RETURN p.name, collect(m.title) AS 영화목록

WITH의 핵심 규칙

WITH 뒤에 명시하지 않은 변수는 사라집니다.

WITH p, count(m) AS cnt → 이후 단계에서 m은 사용 불가

이것은 SQL의 서브쿼리에서 SELECT한 컬럼만 외부에서 보이는 것과 같은 원리입니다.

WITH를 쓰는 대표적 상황

1. 집계 후 필터링 — count한 뒤 WHERE로 거르기
2. 정렬 후 추가 조회 — 상위 N개를 뽑은 뒤 상세 정보 조회
3. 중간 계산 — 계산 결과를 변수에 담아 다음 단계에서 사용

5. UNWIND — 리스트 펼치기

UNWIND는 리스트를 개별 행으로 펼치는 명령어입니다.
collect()가 여러 행을 리스트로 모으는 것의 반대입니다.

리스트를 행으로 펼치기
UNWIND ["인셉션", "매트릭스", "인터스텔라"] AS title
RETURN title

// 결과:
// "인셉션"
// "매트릭스"
// "인터스텔라"
실전: 리스트 데이터를 노드로 일괄 생성
UNWIND [
    {name: "홍길동", age: 30},
    {name: "김철수", age: 25},
    {name: "이영희", age: 28}
] AS person
CREATE (:Person {name: person.name, age: person.age})

collect()와 UNWIND는 짝꿍

collect(): 여러 행 → 하나의 리스트로 모으기
UNWIND: 하나의 리스트 → 여러 행으로 펼치기

데이터를 모았다가 다시 펼치는 패턴은 Cypher에서 자주 사용됩니다.

6. 복합 패턴 — OPTIONAL MATCH · CASE

더 복잡한 조회를 위한 패턴들입니다.

OPTIONAL MATCH — 없어도 NULL로 반환
// 모든 Person을 조회하되, 영화를 안 본 사람도 포함
MATCH (p:Person)
OPTIONAL MATCH (p)-[:WATCHED]->(m:Movie)
RETURN p.name, m.title

// MATCH만 쓰면 영화를 안 본 사람은 결과에서 제외됨
// OPTIONAL MATCH는 SQL의 LEFT JOIN과 같은 역할
CASE — 조건부 값 반환
MATCH (p:Person)
RETURN p.name,
    CASE
        WHEN p.age < 20 THEN "미성년자"
        WHEN p.age < 30 THEN "20대"
        WHEN p.age < 40 THEN "30대"
        ELSE "40대 이상"
    END AS 연령대
ORDER BY · LIMIT · SKIP — 정렬과 페이징
MATCH (m:Movie)
RETURN m.title, m.year
ORDER BY m.year DESC  // 내림차순 정렬
SKIP 10                  // 처음 10개 건너뛰기
LIMIT 5                  // 5개만 반환
7. 핵심 정리
기능 문법 설명
가변 길이 경로 [*1..3] 1~3단계 관계 탐색
최단 경로 shortestPath() 두 노드 간 가장 짧은 경로
집계 count, sum, avg, collect 자동 그룹화 + 집계
중간 파이프 WITH 중간 결과를 다음 단계로 전달
리스트 펼치기 UNWIND 리스트를 개별 행으로 분해
선택적 매칭 OPTIONAL MATCH 없으면 NULL (LEFT JOIN)
조건 분기 CASE WHEN ... END 조건부 값 반환
정렬·페이징 ORDER BY, LIMIT, SKIP 결과 정렬 및 범위 지정

기본 문법 + 고급 문법 = 실전 Cypher

기본 문법(MATCH, CREATE, SET, DELETE)으로 CRUD를 하고,
고급 문법(경로 탐색, WITH, UNWIND, 집계)으로 분석을 합니다.

이 두 페이지를 합치면 실무에서 필요한 Cypher의 90%를 커버합니다.