노드와 관계 패턴
노드와 관계 패턴
Cypher에서 그래프를 조회한다는 것은 곧 "원하는 모양의 패턴을 그려서 매칭한다"는 뜻이에요. 이 페이지에서는 노드 패턴과 관계 패턴을 각각 어떻게 쓰는지, 그리고 라벨·타입을 조합하는 표현식과 프로퍼티 조건을 어떻게 다는지를 문법과 함께 풀어 드릴게요. 패턴 문법만 정확히 알면 거의 모든 Cypher 쿼리를 읽고 쓸 수 있게 돼요.
노드 패턴
노드 패턴은 노드 하나를 매칭하는 패턴이에요. MATCH·EXIST 같은 절에서 단독으로 쓰이거나, 경로 패턴의 일부가 돼요.
문법은 대략 이렇게 생겼어요.
nodePattern ::= "(" [ nodeVariable ] [ labelExpression ] [ propertyKeyValueExpression ] [ elementPatternWhereClause] ")"
elementPatternWhereClause ::= "WHERE" booleanExpression
규칙과 술어
노드 패턴 안에는 세 종류의 술어를 지정할 수 있어요. WHERE 절의 boolean 표현식은 노드 패턴의 스코프 안에 있는 아무 변수나 참조할 수 있고, boolean 표현식에서 변수를 쓰려면 그 변수를 먼저 노드 패턴에서 선언해야 해요. 술어를 하나도 지정하지 않으면 노드 패턴은 아무 노드나 매칭해요.
변수 바인딩도 알아 둘 필요가 있어요. 변수가 쿼리 다른 곳에서 선언되지 않았다면, 그 변수를 포함한 경로 패턴이 매칭될 때 노드에 바인딩돼요. 이전 절에서 이미 바인딩됐다면 새 노드는 바인딩되지 않고, 현재 경로 패턴에서 매칭되지 않는 이전 바인딩 노드는 결과에서 제외돼요.
예시
라벨 A를 가진 모든 노드를 매칭해 변수 n에 바인딩:
(n:A)
라벨 B이고 departs 프로퍼티가 시각 11:11인 노드 매칭:
(:B { departs: time('11:11') })
departs 프로퍼티가 현재 시각에 30분을 더한 값보다 큰 노드 매칭:
(n WHERE n.departs > time() + duration('PT30M'))
관계 패턴
관계 패턴은 관계 하나를 매칭하는 패턴이에요. 반드시 양쪽에 노드 패턴과 함께 쓰여야 해요.
문법은 이렇게 생겼어요.
relationshipPattern ::= fullPattern | abbreviatedRelationship
fullPattern ::= "<-[" patternFiller "]-" | "-[" patternFiller "]->" | "-[" patternFiller "]-"
abbreviatedRelationship ::= "<--" | "--" | "-->"
patternFiller ::= [ relationshipVariable ] [ typeExpression ] [ propertyKeyValueExpression ] [ elementPatternWhereClause ]
관계 패턴의 타입 표현식 문법은 노드 패턴의 라벨 표현식과 같아요. 다만 노드 라벨과 달리 관계는 타입을 정확히 하나만 가져야 한다는 점이 달라요.
규칙과 술어
대괄호를 쓰는 전체 관계 패턴(full pattern)의 채움자에는 세 종류의 술어를 넣을 수 있고, 네 번째로는 화살표 기호(<와 >)로 전체 경로 패턴에 대한 관계 방향을 지정할 수 있어요. 화살표가 없으면 어느 방향이든 매칭해요.
WHERE 절의 boolean 표현식은 관계 패턴 스코프의 변수를 참조할 수 있고, 관계 변수는 패턴에서 선언돼야 해요. 술어가 없으면 모든 관계를 매칭하고, 변수 바인딩 규칙은 노드 패턴과 같아요.
예시
타입 R의 모든 관계를 매칭해 변수 r에 바인딩:
()-[r:R]->()
타입 R이고 distance 프로퍼티가 100인 관계 매칭:
()-[:R {distance: 100}]->()
distance 프로퍼티가 10과 100 사이인 관계 매칭:
()-[r WHERE 10 < r.distance < 100]->()
라벨 A 노드를 출발점으로, 라벨 B 노드를 도착점으로 하는 관계 매칭:
(:A)-->(:B)
라벨 A와 B 노드를 방향과 무관하게 잇는 관계 매칭:
(:A)--(:B)
라벨 표현식
라벨 표현식은 노드 패턴의 라벨과 관계 패턴의 타입 표현식 모두에 적용돼요. 라벨 이름과 와일드카드를 논리합·논리곱·부정·그룹핑으로 조합한 boolean 술어로, 노드가 가진 라벨 집합과 매칭되면 참을 돌려줘요. 관계는 라벨이 아니라 타입을 갖지만, 타입을 매칭하는 문법은 라벨 표현식과 완전히 같아요.
문법은 이렇게 돼요.
labelExpression ::= ":" labelTerm | "IS" [ "NOT" ] "LABELED" labelTerm | "IS NOT" labelTerm
labelTerm ::= labelIdentifier | labelTerm "&" labelTerm | labelTerm "|" labelTerm | "!" labelTerm | "%" | "(" labelTerm ")"
기호의 의미와 우선순위는 이래요.
| 기호 | 설명 | 우선순위 |
|---|---|---|
% |
와일드카드. 라벨 집합이 비어 있지 않으면 참 | |
() |
괄호 안 표현식을 먼저 평가 | 1 (가장 높음) |
! |
부정 | 2 |
& |
논리곱(AND) | 3 |
| |
논리합(OR) | 4 (가장 낮음) |
결합 방향은 왼쪽에서 오른쪽이에요.
예를 들어 (:A&B)는 라벨 A와 B를 모두 가진 노드만 매칭하고, (:A|B)는 둘 중 하나라도 가진 노드를 매칭해요. (:!A)는 라벨 A를 갖지 않은 노드를, (:%)는 라벨이 하나라도 있는 노드를 매칭하죠.
관계는 타입을 정확히 하나 가지므로, 아래 표현식은 어떤 관계도 매칭하지 못해요.
-[:A&B]->
반대로 아래는 모든 관계를 항상 매칭해요.
-[:%]->
부정을 활용하면 관계 패턴에서 논리곱이 유용해져요. 타입이 A도 B도 아닌 관계를 매칭하려면 이렇게 써요.
-[:!A&!B]->
동적 라벨·타입 표현식
노드 라벨과 관계 타입은 라벨 표현식 안에서 표현식·파라미터·변수로 동적으로 참조할 수도 있어요.
dynamicLabelExpression ::= ":$(" + valueExpression ")"
이때 valueExpression은 STRING NOT NULL | LIST<STRING NOT NULL> NOT NULL 값으로 평가돼야 해요.
프로퍼티 key-value 표현식
문법
propertyKeyValueExpression ::= "{" propertyKeyValuePairList "}"
propertyKeyValuePairList ::= propertyKeyValuePair [ "," propertyKeyValuePair ]
propertyKeyValuePair ::= propertyName ":" valueExpression
규칙
프로퍼티 key-value 표현식은 패턴이 매칭하는 요소의 프로퍼티에 대한 등식들의 논리곱으로 취급돼요. 예를 들어 아래 노드 패턴은,
({ p: valueExp1, q: valueExp2 })
다음 WHERE 절을 쓰는 노드 패턴과 동일해요.
(n WHERE n.p = valueExp1 AND n.q = valueExp2)
값 표현식에는 표현식에서 다루는 어떤 표현식이든 쓸 수 있어요. 다만 경로 패턴(문법 오류를 일으킴)과 정규식(문자열 리터럴로 취급)은 제외예요. 빈 프로퍼티 key-value 표현식은 모든 요소를 매칭하고, WHERE 절과 함께 쓸 수도 있어요.
예시
프로퍼티 p가 10인 모든 노드:
({ p: 10 })
프로퍼티 p가 10이고 q가 날짜 2023-02-10인 관계:
()-[{ p: 10, q: date('2023-02-10') }]-()
프로퍼티 p가 출발 노드의 p와 같은 관계:
(s)-[{ p: s.p }]-()
프로퍼티 p가 10이고 q가 100보다 큰 노드:
(n { p: 10 } WHERE n.q > 100)