{#match-match} # MATCH {bdg-primary-line}`GQL 절` 그래프에서 패턴이 들어맞는 모든 자리를 찾고, 일치마다 변수 한 행을 바인딩합니다. {#match-synopsis} ## 개요
[ 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-description} ## 설명 `MATCH`는 그래프를 읽습니다. 자기 패턴을 저장된 정점과 간선 위에 얹을 수 있는 모든 방식마다 행 하나를 내놓습니다. 패턴의 이름 있는 요소는 각각 그것이 일치시킨 정점·간선·경로에 바인딩됩니다. 파이프라인의 뒤따르는 절이 그 바인딩을 봅니다. 파이프라인 가운데의 `MATCH`는 들어오는 행마다 한 번 실행되어 자기 일치를 그 행에 조인하며, 관계형 쿼리에서 조인이 행을 더하는 것과 같습니다. - **변수가 없는** 패턴 요소도 일치됩니다. 뒤에서 그것을 가리킬 수 없을 뿐입니다. 그 요소가 모양을 제약하는 데만 필요하다면 변수를 빼십시오. - **레이블**은 요소를 그 레이블과 자식 레이블로 제한하고, `ONLY`는 그 레이블 자체로 제한합니다. 레이블이 없으면 요소는 그래프의 모든 정점 또는 모든 간선에 일치합니다. - 패턴 안의 **속성 맵**은 그것이 적은 키마다 같음을 검사하는 것입니다. 축약형입니다. `(m:movie {year: 1999})`와 `(m:movie) WHERE m.year = 1999`는 같은 정점에 일치합니다. - **쉼표**는 하나의 `MATCH` 안에서 독립적인 패턴을 구분합니다. 변수를 공유하는 패턴은 그 변수로 조인되고, 아무것도 공유하지 않는 패턴은 곱집합을 만듭니다. - 하나의 패턴 일치 안에서 **같은 간선을 두 번 쓰지 않습니다.** 정점 바인딩은 반복될 수 있어서 패턴이 삼각형을 닫을 수는 있지만, 두 홉 패턴이 자기가 지나온 간선으로 되돌아가는 일은 없습니다. - **간선 변수**는 패턴마다 한 번만 쓸 수 있습니다. 다시 쓰면 `duplicate variable`이 나옵니다. **정점 변수**는 반복할 수 있고, 그러면 두 자리가 같은 정점으로 제약됩니다. - `MATCH`는 쿼리를 시작하거나 첫 절 뒤 어디에든 놓일 수 있습니다. 쿼리를 끝내지는 않습니다. 쿼리는 `RETURN`, `FINISH`, 또는 쓰기 절로 끝나야 합니다. `OPTIONAL MATCH`는 패턴이 아무것도 찾지 못한 입력 행을 남기고, 그 행을 버리는 대신 패턴의 변수를 null로 바인딩합니다. 그것은 자기 페이지가 있습니다. [`OPTIONAL MATCH`](optional-match.md)입니다. {#match-parameters} ## 매개변수 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`](where.md)를 참고하십시오. {#match-examples} ## 예제 모든 예제는 [예제 데이터셋](../../get_started/example-dataset.md)에서 실행됩니다. {#match-find-one-vertex-by-a-property} ### 속성으로 정점 하나 찾기 ```cypher 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-follow-an-edge-in-one-direction} ### 한 방향으로 간선 따라가기 ```cypher 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-leave-out-the-elements-you-do-not-need} ### 필요하지 않은 요소 빼기 ```cypher MATCH (p:person {name: 'Christopher Nolan'})-[:directed]->(m) RETURN m.title AS film ORDER BY film; ``` ``` film ---------------- "Inception" "Interstellar" (2 rows) ``` 간선에는 변수가 없고 먼 쪽 끝점에는 레이블이 없습니다. 둘 다 여전히 일치를 제약하며, 어느 쪽도 바인딩 비용을 들이지 않습니다. {#match-match-an-edge-in-either-direction} ### 어느 방향이든 간선 일치시키기 화살촉이 없는 간선 패턴은 간선이 어느 쪽을 가리키든 일치시킵니다: ```cypher 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-join-two-patterns-on-a-shared-variable} ### 공유 변수로 두 패턴 조인하기 ```cypher 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)`도 그렇습니다. {#match-name-the-whole-path} ### 경로 전체에 이름 붙이기 경로 자체를 바인딩하려면 패턴 앞에 `variable =`을 두십시오: ```cypher 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-walk-a-variable-number-of-edges} ### 정해지지 않은 수의 간선 걷기 간선 패턴에 붙인 `*`가 그것을 반복합니다. 각 경계는 생략할 수 있습니다: ```cypher 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인 경로가 포함되므로, 시작 정점도 답 중 하나가 됩니다: ```cypher 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) ``` {#match-exclude-child-labels-with-only} ### ONLY로 자식 레이블 제외하기 레이블은 자식 레이블에도 일치합니다. 레이블이 테이블이고 자식 레이블이 그것을 상속하기 때문입니다. `ONLY`는 일치 범위를 그 레이블 하나로 좁힙니다. 차이를 보려면 `person`에 자식 레이블을 하나 주십시오: ```cypher CREATE VLABEL crew INHERITS (person); CREATE (:crew {name: 'Bill Pope', born: 1952}); ``` ``` CREATE VLABEL UPDATE 1 ``` ```cypher MATCH (p:person) RETURN count(*) AS people; ``` ``` people -------- 29 (1 row) ``` ```cypher MATCH (p:person ONLY) RETURN count(*) AS people; ``` ``` people -------- 28 (1 row) ``` `ONLY`는 레이블 뒤, 속성 맵 앞에 놓입니다. `(p:person ONLY {name: 'Keanu Reeves'})`처럼입니다. 간선 패턴 `-[r:acted_in ONLY]->`에서도 같게 동작합니다. 준비한 것은 이렇게 되돌립니다: ```cypher MATCH (p:crew) DETACH DELETE p; DROP VLABEL crew; ``` ``` UPDATE 1 DROP VLABEL ``` {#match-filter-the-matches-with-where} ### WHERE로 일치 결과 걸러 내기 `MATCH`에 붙인 `WHERE`는 뒤에 오는 단계가 아니라 그 일치의 일부입니다: ```cypher 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-match-edges-of-several-labels} ### 여러 레이블의 간선 일치시키기 간선 패턴에는 레이블이 최대 하나입니다. 둘을 나열하면 오류가 납니다: ```cypher MATCH (p:person)-[r:acted_in|directed]->(m:movie) RETURN count(r); ``` ``` ERROR: multiple types for relationship not supported ``` 대신 레이블 없는 간선을 일치시키고 그 레이블을 `WHERE`에서 검사하십시오: ```cypher MATCH (p:person)-[r]->(m:movie) WHERE label(r) IN ['acted_in', 'directed'] RETURN count(r) AS edges; ``` ``` edges ------- 46 (1 row) ``` `label()`은 요소의 레이블을 문자열로 반환합니다. 그래서 이름 목록에 대한 `IN`이 일반적인 형태이고, 간선 레이블의 집합에 일치시키는 유일한 방법입니다. {#match-notes} ## 참고 레이블 검사는 `WHERE` 안의 콜론이 아니라 `label(n) = '...'`에 씁니다. `WHERE n:movie`는 구문 오류이고, 패턴만 조건으로 쓴 것도 그렇습니다. `WHERE (m)-[:related_to]->(:movie)`는 파싱되지 않습니다. 패턴이 존재하는지 검사하려면 `WHERE EXISTS { MATCH (m)-[:related_to]->(:movie) }`를 쓰십시오. 속성 맵은 jsonb 값을 비교하고, 속성과의 비교도 그렇습니다. 리터럴의 타입이 저장된 타입과 맞지 않을 때 그것이 문제가 됩니다. [`WHERE`](where.md)를 참고하십시오. ```{note} 이름 붙인 경로 변수는 요소 변수보다 좁게 파싱됩니다. `(path)`는 받아들여지는 정점 변수이지만, `path`가 키워드이므로 `MATCH path = ...`는 구문 오류입니다. `MATCH p = ...`로 쓰거나 그 이름을 따옴표로 감싸십시오. ``` {#match-compatibility} ## 호환성 {#match-label-expressions-isoiec-39075-168} ### 레이블 표현식 (ISO/IEC 39075 §16.8) 표준의 `