MATCH#

GQL 절

그래프에서 패턴이 들어맞는 모든 자리를 찾고, 일치마다 변수 한 행을 바인딩합니다.

개요#

[ OPTIONAL ] MATCH pattern [, pattern ] ... [ WHERE condition ]

여기서 pattern은 정점 패턴과 간선 패턴을 이어 놓은 것이며, 이름을 붙일 수도 있습니다:

[ path_variable = ] node [ edge node ] ...

node는 소괄호로 씁니다:

( [ variable ] [ : label [ ONLY ] ] [ { property_map } ] )

edge는 하이픈 두 개 사이의 대괄호로 쓰고, 그 안에 edge_body를 둡니다:

[ variable ] [ : label [ ONLY ] ] [ * [ min ] [ .. [ max ] ] ] [ { property_map } ]

그 주위의 하이픈과 화살촉이 방향을 나타냅니다. 세 가지가 있습니다:

-[ edge_body ]->      left to right
<-[ edge_body ]-      right to left
-[ edge_body ]-       either direction

굵게 키워드 · 기울임 직접 채우는 자리 · [ ] 생략 가능 · ... 반복 가능. 구문 표기 규약을 참고하십시오.

설명#

MATCH는 그래프를 읽습니다. 자기 패턴을 저장된 정점과 간선 위에 얹을 수 있는 모든 방식마다 행 하나를 내놓습니다. 패턴의 이름 있는 요소는 각각 그것이 일치시킨 정점·간선·경로에 바인딩됩니다. 파이프라인의 뒤따르는 절이 그 바인딩을 봅니다. 파이프라인 가운데의 MATCH는 들어오는 행마다 한 번 실행되어 자기 일치를 그 행에 조인하며, 관계형 쿼리에서 조인이 행을 더하는 것과 같습니다.

  • 변수가 없는 패턴 요소도 일치됩니다. 뒤에서 그것을 가리킬 수 없을 뿐입니다. 그 요소가 모양을 제약하는 데만 필요하다면 변수를 빼십시오.

  • 레이블은 요소를 그 레이블과 자식 레이블로 제한하고, ONLY는 그 레이블 자체로 제한합니다. 레이블이 없으면 요소는 그래프의 모든 정점 또는 모든 간선에 일치합니다.

  • 패턴 안의 속성 맵은 그것이 적은 키마다 같음을 검사하는 것입니다. 축약형입니다. (m:movie {year: 1999})와 (m:movie) WHERE m.year = 1999는 같은 정점에 일치합니다.

  • 쉼표는 하나의 MATCH 안에서 독립적인 패턴을 구분합니다. 변수를 공유하는 패턴은 그 변수로 조인되고, 아무것도 공유하지 않는 패턴은 곱집합을 만듭니다.

  • 하나의 패턴 일치 안에서 같은 간선을 두 번 쓰지 않습니다. 정점 바인딩은 반복될 수 있어서 패턴이 삼각형을 닫을 수는 있지만, 두 홉 패턴이 자기가 지나온 간선으로 되돌아가는 일은 없습니다.

  • 간선 변수는 패턴마다 한 번만 쓸 수 있습니다. 다시 쓰면 duplicate variable이 나옵니다. 정점 변수는 반복할 수 있고, 그러면 두 자리가 같은 정점으로 제약됩니다.

  • MATCH는 쿼리를 시작하거나 첫 절 뒤 어디에든 놓일 수 있습니다. 쿼리를 끝내지는 않습니다. 쿼리는 RETURN, FINISH, 또는 쓰기 절로 끝나야 합니다.

OPTIONAL MATCH는 패턴이 아무것도 찾지 못한 입력 행을 남기고, 그 행을 버리는 대신 패턴의 변수를 null로 바인딩합니다. 그것은 자기 페이지가 있습니다. OPTIONAL MATCH입니다.

매개변수#

pattern

경로 패턴 하나이며, 앞에 path_variable =을 붙일 수도 있습니다. 쉼표로 구분해 여러 개 나열할 수 있습니다.

path_variable

일치한 경로 전체에 바인딩되는 이름이며, 그 정점과 간선을 순서대로 담은 값입니다. 경로 함수 length()·nodes()·edges()로 읽습니다. 그 이름은 식별자여야 합니다. path처럼 예약되지 않은 키워드도 따옴표로 감싸지 않으면("path") 이 자리에서는 거부됩니다.

variable

일치한 정점이나 간선에 바인딩되는 이름입니다. 생략할 수 있습니다. 이 절 뒤의 모든 절에서 보입니다.

label

정점 패턴에서는 정점 레이블, 간선 패턴에서는 간선 레이블입니다. 요소마다 레이블 하나입니다.

ONLY

자식 레이블을 제외하므로, 그 요소는 해당 레이블 자기 테이블의 행에만 일치하고 그것을 상속한 것에는 일치하지 않습니다. 레이블이 있어야 합니다.

property_map

맵 리터럴, 또는 그것을 담은 쿼리 매개변수입니다. 각 키는 그 요소의 같은 이름 속성과 같은지 비교됩니다.

min, max

가변 길이 간선 패턴이 지나는 간선 수의 경계입니다. *n은 정확히 n 홉, *m..n은 m과 n 사이, *m..은 m 이상, *..n은 n 이하, *만 쓰면 하나 이상입니다.

condition

일치 결과를 걸러 내는 불리언 표현식이며, 패턴의 모든 변수가 바인딩된 상태에서 평가됩니다. WHERE를 참고하십시오.

예제#

모든 예제는 예제 데이터셋에서 실행됩니다.

속성으로 정점 하나 찾기#

MATCH (p:person {name: 'Keanu Reeves'})
RETURN p;
                         p
---------------------------------------------------
 person[4.1]{"born": 1964, "name": "Keanu Reeves"}
(1 row)

정점은 label[id]{properties} 형태로 출력됩니다. 4.1이 그 그래프 id이고, id(p)로 읽습니다. p.id는 id라는 이름의 속성을 읽는 것이고, 그런 속성은 없습니다.

한 방향으로 간선 따라가기#

MATCH (p:person)-[r:acted_in]->(m:movie {title: 'The Matrix'})
RETURN p.name AS actor, r.role AS role
ORDER BY actor;
        actor         |    role
----------------------+------------
 "Carrie-Anne Moss"   | "Trinity"
 "Keanu Reeves"       | "Neo"
 "Laurence Fishburne" | "Morpheus"
(3 rows)

양 끝점과 간선 모두에 레이블이 있고, 간선은 r에 바인딩되어 그 role 속성을 투영할 수 있습니다. Cypher의 RETURN이 jsonb를 내놓으므로 문자열 값은 따옴표와 함께 돌아옵니다.

필요하지 않은 요소 빼기#

MATCH (p:person {name: 'Christopher Nolan'})-[:directed]->(m)
RETURN m.title AS film
ORDER BY film;
      film
----------------
 "Inception"
 "Interstellar"
(2 rows)

간선에는 변수가 없고 먼 쪽 끝점에는 레이블이 없습니다. 둘 다 여전히 일치를 제약하며, 어느 쪽도 바인딩 비용을 들이지 않습니다.

어느 방향이든 간선 일치시키기#

화살촉이 없는 간선 패턴은 간선이 어느 쪽을 가리키든 일치시킵니다:

MATCH (m:movie {title: 'Total Recall'})-[:related_to]-(n:movie)
RETURN n.title AS neighbour
ORDER BY neighbour;
  neighbour
--------------
 "Inception"
 "The Matrix"
(2 rows)

Total Recall에는 나가는 related_to 간선 하나와 들어오는 것 하나가 있습니다. 양쪽 끝에 화살촉을 붙인 <-[:related_to]->도 같은 뜻입니다.

공유 변수로 두 패턴 조인하기#

MATCH (a:person)-[:acted_in]->(m:movie), (d:person)-[:directed]->(m)
WHERE m.title = 'The Matrix'
RETURN a.name AS actor, d.name AS director
ORDER BY actor, director;
        actor         |     director
----------------------+-------------------
 "Carrie-Anne Moss"   | "Lana Wachowski"
 "Carrie-Anne Moss"   | "Lilly Wachowski"
 "Keanu Reeves"       | "Lana Wachowski"
 "Keanu Reeves"       | "Lilly Wachowski"
 "Laurence Fishburne" | "Lana Wachowski"
 "Laurence Fishburne" | "Lilly Wachowski"
(6 rows)

두 패턴 모두 m을 언급하므로 그것으로 조인됩니다. 연달아 오는 MATCH 절 두 개도 같은 결과를 낼 것이고, 가운데에서 만나는 하나의 패턴 (a:person)-[:acted_in]->(m:movie)<-[:directed]-(d:person)도 그렇습니다.

경로 전체에 이름 붙이기#

경로 자체를 바인딩하려면 패턴 앞에 variable =을 두십시오:

MATCH p = (a:movie {title: 'The Matrix'})-[:related_to*1..3]->(b:movie)
RETURN length(p) AS hops, [x IN nodes(p) | x.title] AS route
ORDER BY hops, route;
 hops |                                            route
------+---------------------------------------------------------------------------------------------
 1    | ["The Matrix", "The Matrix Reloaded"]
 1    | ["The Matrix", "The Terminator"]
 1    | ["The Matrix", "Total Recall"]
 2    | ["The Matrix", "The Matrix Reloaded", "The Matrix Revolutions"]
 2    | ["The Matrix", "The Terminator", "Terminator 2: Judgment Day"]
 2    | ["The Matrix", "Total Recall", "Inception"]
 3    | ["The Matrix", "The Matrix Reloaded", "The Matrix Revolutions", "The Matrix Resurrections"]
(7 rows)

정해지지 않은 수의 간선 걷기#

간선 패턴에 붙인 *가 그것을 반복합니다. 각 경계는 생략할 수 있습니다:

MATCH (m:movie {title: 'The Matrix'})-[:related_to*2]->(n:movie)
RETURN n.title AS reached
ORDER BY reached;
           reached
------------------------------
 "Inception"
 "Terminator 2: Judgment Day"
 "The Matrix Revolutions"
(3 rows)

하한이 0이면 길이 0인 경로가 포함되므로, 시작 정점도 답 중 하나가 됩니다:

MATCH (m:movie {title: 'The Matrix'})-[:related_to*0..1]->(n:movie)
RETURN n.title AS reached
ORDER BY reached;
        reached
-----------------------
 "The Matrix"
 "The Matrix Reloaded"
 "The Terminator"
 "Total Recall"
(4 rows)

ONLY로 자식 레이블 제외하기#

레이블은 자식 레이블에도 일치합니다. 레이블이 테이블이고 자식 레이블이 그것을 상속하기 때문입니다. ONLY는 일치 범위를 그 레이블 하나로 좁힙니다. 차이를 보려면 person에 자식 레이블을 하나 주십시오:

CREATE VLABEL crew INHERITS (person);
CREATE (:crew {name: 'Bill Pope', born: 1952});
CREATE VLABEL
UPDATE 1
MATCH (p:person) RETURN count(*) AS people;
 people
--------
 29
(1 row)
MATCH (p:person ONLY) RETURN count(*) AS people;
 people
--------
 28
(1 row)

ONLY는 레이블 뒤, 속성 맵 앞에 놓입니다. (p:person ONLY {name: 'Keanu Reeves'})처럼입니다. 간선 패턴 -[r:acted_in ONLY]->에서도 같게 동작합니다. 준비한 것은 이렇게 되돌립니다:

MATCH (p:crew) DETACH DELETE p;
DROP VLABEL crew;
UPDATE 1
DROP VLABEL

WHERE로 일치 결과 걸러 내기#

MATCH에 붙인 WHERE는 뒤에 오는 단계가 아니라 그 일치의 일부입니다:

MATCH (m:movie) WHERE m.year > 2015
RETURN m.title AS film, m.year AS year
ORDER BY year, film;
            film            | year
----------------------------+------
 "Blade Runner 2049"        | 2017
 "The Matrix Resurrections" | 2021
(2 rows)

여러 레이블의 간선 일치시키기#

간선 패턴에는 레이블이 최대 하나입니다. 둘을 나열하면 오류가 납니다:

MATCH (p:person)-[r:acted_in|directed]->(m:movie) RETURN count(r);
ERROR:  multiple types for relationship not supported

대신 레이블 없는 간선을 일치시키고 그 레이블을 WHERE에서 검사하십시오:

MATCH (p:person)-[r]->(m:movie)
WHERE label(r) IN ['acted_in', 'directed']
RETURN count(r) AS edges;
 edges
-------
 46
(1 row)

label()은 요소의 레이블을 문자열로 반환합니다. 그래서 이름 목록에 대한 IN이 일반적인 형태이고, 간선 레이블의 집합에 일치시키는 유일한 방법입니다.

참고#

레이블 검사는 WHERE 안의 콜론이 아니라 label(n) = '...'에 씁니다. WHERE n:movie는 구문 오류이고, 패턴만 조건으로 쓴 것도 그렇습니다. WHERE (m)-[:related_to]->(:movie)는 파싱되지 않습니다. 패턴이 존재하는지 검사하려면 WHERE EXISTS { MATCH (m)-[:related_to]->(:movie) }를 쓰십시오.

속성 맵은 jsonb 값을 비교하고, 속성과의 비교도 그렇습니다. 리터럴의 타입이 저장된 타입과 맞지 않을 때 그것이 문제가 됩니다. WHERE를 참고하십시오.

참고

이름 붙인 경로 변수는 요소 변수보다 좁게 파싱됩니다. (path)는 받아들여지는 정점 변수이지만, path가 키워드이므로 MATCH path = ...는 구문 오류입니다. MATCH p = ...로 쓰거나 그 이름을 따옴표로 감싸십시오.

호환성#

레이블 표현식 (ISO/IEC 39075 §16.8)#

표준의 <label expression>은 레이블 이름을 논리합은 |, 논리곱은 &, 부정은 !로 엮습니다. AgensGraph는 패턴 요소마다 레이블 이름 하나만 받으므로 셋 중 어느 것도 쓸 수 없습니다. -[r:acted_in|directed]->는 multiple types for relationship not supported를 내고, -[r:acted_in|:directed]->는 구문 오류입니다. openCypher도 논리합을 파이프로 표기하는데, 여기서는 고정 길이 간선, 가변 길이 간선, shortestpath 안에서 모두 거부됩니다. 위에 보인 WHERE label(r) IN [...]을 쓰십시오.

레이블 술어 (ISO/IEC 39075 §19.9)#

표준은 레이블 검사를 n IS LABELED movie 또는 n:movie로 씁니다. AgensGraph는 두 표기 모두 받지 않습니다. label(n) = 'movie'를 쓰십시오.

ONLY 수정자 (ISO/IEC 39075 §16.7)#

표준의 <element pattern filler>는 변수 선언, 레이블 표현식, 조건을 담고 그 밖에는 아무것도 담지 않습니다. ONLY가 없습니다. AgensGraph가 그것을 더한 것은, 여기서 레이블이 자식 레이블이 상속하는 테이블이고 따라서 레이블 일치가 상속 트리 전체에 대한 일치이기 때문입니다. 레이블 상속을 참고하십시오.

관련 항목#

  • OPTIONAL MATCH — 패턴이 일치시키지 못한 행 남기기

  • WHERE — 일치가 지닐 수 있는 조건

  • CREATE와 MERGE — 쓰기에 쓰는, 같은 패턴 구문

  • LOAD FROM — 같은 파이프라인으로 테이블을 읽어 들이기

  • 함수 — length(), nodes(), edges()와 그 밖의 경로 함수

  • 쿼리하기 — shortestpath·allshortestpaths·dijkstra 형태를 포함한 경로 쿼리