{#path-path-functions} # 경로 함수 `graphpath`에 대한 함수들과, 그것을 만들어 내는 세 가지 경로 탐색 형태입니다. `graphpath`는 `MATCH p = (...)`가 바인딩하는, 정점과 간선이 번갈아 오는 나열입니다. 경로는 이름을 붙여 바인딩합니다. `MATCH p = (a)-[r]->(b)`처럼입니다. 이 함수들은 패턴이 아니라 그 *변수*를 받습니다. 예제는 [예제 데이터셋](../../get_started/example-dataset.md)에서 실행됩니다. {#path-allshortestpaths} ## allshortestpaths ``` allshortestpaths ( pattern ) -> graphpath ``` 두 정점 사이의 모든 최단 경로를 찾습니다. 경로 변수에 이름을 붙이면 경로마다 한 행을 반환하고, 표현식으로 쓰면 경로의 배열을 반환합니다. **고려할 점** - 패턴에는 관계가 정확히 하나 있어야 하며, 그렇지 않으면 파서가 `only one relationship is allowed`를 냅니다. 홉을 더 적는 대신 그 관계에 `*..4` 같은 길이 범위를 주십시오. - 여러 타입을 쓴 관계 패턴은 어디서도 지원되지 않으며 `allshortestpaths`도 그렇습니다. 타입 없는 간선을 일치시키고 `WHERE label(r) IN [...]`으로 걸러 내십시오. - 표현식으로 쓰면 `graphpath[]`를 내놓으므로, 그것에 대한 `length()`는 한 경로의 간선 수가 아니라 찾아낸 경로의 개수를 셉니다. ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'Inception'}) RETURN length(allshortestpaths((a)-[:related_to*..4]->(b))) AS paths_found; ``` ``` paths_found ------------- 1 ``` {#path-dijkstra} ## dijkstra ``` dijkstra ( pattern, weight ) -> graphpath dijkstra ( pattern, weight, condition ) -> graphpath dijkstra ( pattern, weight, LIMIT count ) -> graphpath dijkstra ( pattern, weight, condition, LIMIT count ) -> graphpath ``` 두 정점 사이의 가장 값싼 경로를 찾습니다. 각 간선의 비용은 `weight`가 평가된 값입니다. | 이름 | 타입 | 설명 | | --- | --- | --- | | `pattern` | 경로 사슬 | 두 정점 사이의 관계 정확히 하나입니다. 예를 들어 `(a)-[e:related_to]->(b)`입니다. `weight`가 그 관계의 속성을 읽는다면 관계에 변수를 주십시오. | | `weight` | 수치 표현식 | 간선 하나를 지나는 비용입니다. 고려되는 모든 간선에서 0보다 커야 합니다. | | `condition` | 불리언 표현식 | 간선에 대한 선택적 필터입니다. 이것을 만족하는 간선만 지나갑니다. | | `count` | 정수 | 선택 사항입니다. 값싼 것부터 반환할 대안 경로의 개수입니다. 0보다 커야 합니다. | **고려할 점** - 패턴의 일부로 적으면 경로를 바인딩합니다. `p = dijkstra(...)`입니다. `(p, w) = dijkstra(...)`로 적으면 경로*와* 그 총 가중치를 바인딩하며, 그 값은 그 밖의 방법으로는 얻을 수 없습니다. - `LIMIT`이 없으면 개수의 기본값이 1이므로 경로 하나가 돌아옵니다. - 패턴은 속성 제약도, 가변 길이 관계도 받지 않습니다. 대신 `WHERE`에서 걸러 내십시오. ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'Inception'}), p = dijkstra((a:movie {title:'The Matrix'})-[e:related_to]->(b), e.weight) RETURN p; ``` ``` ERROR: property constraint is not supported LINE 2: p = dijkstra((a:movie {title:'The Matrix'})-[e:related... ^ ``` ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'Inception'}), p = dijkstra((a)-[e:related_to*]->(b), e.weight) RETURN p; ``` ``` ERROR: variable length relationship is not supported ``` - 세 번째 위치 인자는 조건이므로, 그 자리에 숫자를 두면 `cannot cast 1 (jsonb type numeric) to boolean`이 나옵니다. - 거부가 두 개 더 있는데 간선에 도달한 뒤 실행 시점에 나오므로, 쿼리만이 아니라 데이터에 달려 있습니다. 0 이하로 평가되는 가중치는 `WEIGHT must be larger than 0`을, `LIMIT 0`은 `LIMIT must be larger than 0`을 보고합니다. - 할당하지 않고 표현식으로만 쓰면 `graphpath[]`를 내놓습니다. 가장 값싼 경로가 가장 짧은 경로는 아닙니다. *Total Recall*을 지나는 두 홉의 비용은 4 + 2이고, 이 그래프에서는 그것이 한 홉 대안들을 이깁니다: ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'Inception'}), (p, w) = dijkstra((a)-[e:related_to]->(b), e.weight) RETURN [x IN nodes(p) | x.title] AS route, w AS weight; ``` ``` route | weight ---------------------------------------------+-------- ["The Matrix", "Total Recall", "Inception"] | 6 ``` 먼 쪽 끝점을 제약하지 않으면 도달할 수 있는 모든 영화까지의 가장 값싼 경로가 나옵니다: ```cypher MATCH p = dijkstra((a:movie)-[e:related_to]->(b:movie), e.weight, LIMIT 1) WHERE a.title = 'The Matrix' RETURN [x IN nodes(p) | x.title] AS route ORDER BY route; ``` ``` route --------------------------------------------------------------------------------------------- ["The Matrix"] ["The Matrix", "The Matrix Reloaded"] ["The Matrix", "The Terminator"] ["The Matrix", "Total Recall"] ["The Matrix", "The Matrix Reloaded", "The Matrix Revolutions"] ["The Matrix", "The Terminator", "Terminator 2: Judgment Day"] ["The Matrix", "Total Recall", "Inception"] ["The Matrix", "The Matrix Reloaded", "The Matrix Revolutions", "The Matrix Resurrections"] ``` `ORDER BY`가 없으면 행은 특정한 순서 없이 돌아옵니다. 위의 정렬은 지면을 재현 가능하게 만들기 위한 것뿐입니다. ```{note} `dijkstra`가 찾은 경로도 다른 것과 같은 `graphpath`이므로 `nodes()`·`relationships()`·`length()`가 모두 그것을 읽습니다. 다른 경로가 지니지 않는 것은 총 가중치이고, 그것을 드러내는 것은 `(p, w) =` 형태뿐입니다. ``` {#path-edges} ## edges ``` edges ( p graphpath ) -> edge[] ``` 경로의 간선을 순서대로 반환합니다. [`relationships`](#path-relationships)가 Cypher가 쓰는 이름으로 부른 같은 함수입니다. {#path-end_vertex} ## end_vertex ``` end_vertex ( e edge ) -> vertex ``` 간선이 가리키는 정점을 반환합니다. `endNode`가 Cypher가 쓰는 이름으로 부른 같은 함수이며, 둘 다 [스칼라 페이지](#scalar-endnode)에 나열돼 있습니다. **고려할 점** - 정점을 읽는다는 것은 그 행을 가져온다는 뜻입니다. 식별자만으로 충분하다면 간선 자신의 컬럼을 읽는 [`end_id`](#scalar-end_id)를 쓰십시오. {#path-length} ## length ``` length ( p graphpath ) -> jsonb length ( vs vertex[] ) -> jsonb length ( es edge[] ) -> jsonb length ( ps graphpath[] ) -> jsonb ``` 경로에 대해서는 그 안의 간선 수를, 배열에 대해서는 요소 수를 반환합니다. **고려할 점** - 요소 수가 아니라 간선 수입니다. 간선 하나인 경로의 길이는 1이지만 같은 경로의 [`cardinality`](#list-cardinality)는 3입니다. - `allshortestpaths()`와 할당하지 않은 `dijkstra()`가 `graphpath[]`를 내놓으므로, 그런 것에 대한 `length()`는 경로의 개수를 셉니다. - 문자열·리스트·맵에 대한 `length`는 다른 함수입니다. 스칼라 페이지의 [`length`](#scalar-length)를 참고하십시오. ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'The Matrix Resurrections'}) RETURN length(shortestpath((a)-[:related_to*]->(b))) AS hops; ``` ``` hops ------ 3 ``` {#path-nodes} ## nodes ``` nodes ( p graphpath ) -> vertex[] ``` 경로의 정점을 순서대로 반환하며, 그 경로가 시작하는 정점부터 시작합니다. **고려할 점** - 결과는 네이티브 배열인 `vertex[]`이므로 Cypher의 `RETURN`이 그것을 `jsonb`로 감싸지 않습니다. 첨자는 여전히 0부터입니다. - `vertices`가 다른 이름으로 부른 같은 함수입니다. - 경로 *변수*를 넘기십시오. 그 자리에 적은 패턴은 표현식이 아니어서 파싱되지 않습니다. - 정점 전체를 출력하는 것이 원하는 것인 경우는 드뭅니다. 하나하나가 자기 `properties`를 온전히 지니고 있기 때문입니다. 아래처럼 리스트 컴프리헨션으로 필요한 항목만 투영하십시오. ```cypher MATCH p=(:person {name:'Christopher Nolan'})-[:directed]->(:movie {title:'Inception'}) RETURN [x IN nodes(p) | x.name] AS names, [x IN nodes(p) | x.title] AS titles; ``` ``` names | titles -----------------------------+--------------------- ["Christopher Nolan", null] | [null, "Inception"] ``` 경로의 모든 정점이 투영되므로, 어떤 정점이 지니고 있지 않은 키는 null로 돌아옵니다. {#path-relationships} ## relationships ``` relationships ( p graphpath ) -> edge[] ``` 경로의 간선을 순서대로 반환합니다. [`edges`](#path-edges)와 동일합니다. ```cypher MATCH p=(:person {name:'Christopher Nolan'})-[:directed]->(:movie {title:'Inception'}) RETURN relationships(p) AS edges; ``` ``` edges ---------------------------- [directed[6.8][4.8,3.5]{}] ``` {#path-shortestpath} ## shortestpath ``` shortestpath ( pattern ) -> graphpath ``` 두 정점 사이의 최단 경로 하나를 간선 수 기준으로 찾습니다. 똑같이 짧은 것이 여럿이면 그중 하나가 반환됩니다. **고려할 점** - 패턴에는 관계가 정확히 하나 있어야 하고, 길이 범위는 그 관계가 지닙니다. 홉을 늘여 쓰는 것은 거부됩니다: ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'Inception'}) RETURN shortestpath((a)-[:related_to]->()-[:related_to]->(b)); ``` ``` ERROR: only one relationship is allowed LINE 2: RETURN shortestpath((a)-[:related_to]->()-[:related_to]->(b)... ^ ``` - 똑같이 짧은 경로가 여럿일 때 어느 것을 받는지는 정해져 있지 않습니다. 전부 필요하면 [`allshortestpaths`](#path-allshortestpaths)를 쓰십시오. - 경로가 없으면 null인 경로가 아니라 아무 행도 반환하지 않습니다. - 여러 타입을 쓴 관계 패턴은 여기서도 지원되지 않습니다. ```cypher MATCH (a:movie {title:'The Matrix'}), (b:movie {title:'The Matrix Resurrections'}) RETURN [x IN nodes(shortestpath((a)-[:related_to*]->(b))) | x.title] AS route; ``` ``` route --------------------------------------------------------------------------------------------- ["The Matrix", "The Matrix Reloaded", "The Matrix Revolutions", "The Matrix Resurrections"] ``` {#path-start_vertex} ## start_vertex ``` start_vertex ( e edge ) -> vertex ``` 간선이 떠나는 정점을 반환합니다. `startNode`가 Cypher가 쓰는 이름으로 부른 같은 함수입니다. [`startNode`](#scalar-startnode)를 참고하십시오. 정점은 복합 타입이므로, 그 결과에서 속성을 곧바로 읽을 수 있습니다: ```cypher MATCH (:person {name:'Keanu Reeves'})-[e:acted_in]->(:movie {title:'The Matrix'}) RETURN start_vertex(e).name AS actor, end_vertex(e).title AS film; ``` ``` actor | film ----------------+-------------- "Keanu Reeves" | "The Matrix" ``` {#path-vertices} ## vertices ``` vertices ( p graphpath ) -> vertex[] ``` 경로의 정점을 순서대로 반환합니다. [`nodes`](#path-nodes)와 동일합니다. {#path-compatibility} ## 호환성 {#path-opencypher} ### openCypher `shortestPath`와 `allShortestPaths`는 대소문자를 가리지 않고 표기되므로 openCypher의 대소문자 표기도 동작합니다. openCypher에는 `dijkstra`가 없습니다. 거기서 가중 최단 경로는 프로시저 라이브러리에서 옵니다. openCypher는 `-[r:acted_in|directed]->`처럼 관계 패턴이 여러 타입을 이름으로 부르는 것을 허용합니다. 여기서 그것은 모든 길이에서, 모든 경로 탐색 형태 안에서 `multiple types for relationship not supported`를 냅니다. 대신 타입 없는 관계를 일치시키고 레이블을 검사하십시오: ```cypher MATCH (p:person)-[r]->(m:movie) WHERE label(r) IN ['acted_in','directed'] RETURN count(r) AS n; ``` ``` n ---- 46 ``` {#path-see-also} ## 관련 항목 - [모든 함수](all-functions.md) — 모든 함수를 한 표에 - [스칼라 함수](scalar.md) — `startNode`, `endNode`, `start_id`, `end_id` - [리스트 함수](list.md) — 경로에 대한 `cardinality` - [구문](../syntax.md) — 경로 패턴과 유연한 길이