레이블 상속#
레이블은 다른 레이블을 상속할 수 있습니다. 자식은 자기 id 시퀀스와 자기 행을 가진 별개의 레이블이지만, 부모를 이름으로 부르는 패턴은 자식의 행에도 일치합니다. 덕분에 계열 전체를 하나의 패턴으로 쿼리하는 능력을 포기하지 않고도 타입 계층을 가질 수 있습니다.
이 상속은 PostgreSQL의 테이블 상속입니다 — 레이블은 테이블이고,
레이블에 준 INHERITS는 그 테이블의 INHERITS가 됩니다.
계층 선언하기#
이 페이지의 예제는 예제 데이터셋을 쓰지 않고 자체의 작은
그래프를 만듭니다. 상속은 영화와 사람보다 계층 구조에서 보기가 쉽기 때문입니다. 다 보고 나면
DROP GRAPH inh CASCADE;를 실행하십시오.
CREATE GRAPH inh;
SET graph_path = inh;
CREATE VLABEL work;
CREATE VLABEL film INHERITS (work);
CREATE VLABEL series INHERITS (work);
CREATE (:film {title: 'A'}), (:series {title: 'B'}), (:work {title: 'C'});
부모를 이름으로 부르면 계열의 모든 행에 일치합니다:
MATCH (n:work) RETURN label(n) AS label, n.title AS t ORDER BY t;
label | t
----------+-----
"film" | "A"
"series" | "B"
"work" | "C"
자식을 이름으로 부르면 그 자식에만 일치합니다:
MATCH (n:film) RETURN label(n) AS label, n.title AS t;
label | t
--------+-----
"film" | "A"
label(n)이 무엇을 반환하는지 보십시오. 정점이 만들어질 때의 레이블이고, 부모는 결코 아닙니다.
정점은 정확히 하나의 레이블에 속합니다. “부모에 일치한다”는 것은 패턴이 어느 테이블을 스캔하는지에
대한 이야기이고, 정점이 레이블 두 개를 갖는다는 이야기가 아닙니다.
ONLY: 자식을 제외하기#
ONLY는 패턴을 이름으로 부른 그 레이블 자체로 제한합니다:
MATCH (n:work ONLY) RETURN label(n) AS label, n.title AS t;
label | t
--------+-----
"work" | "C"
간선에도 쓸 수 있고, 대괄호 안에 적습니다:
MATCH ()-[e:rel ONLY]->() RETURN count(e) AS n;
n
---
0
이 0이 바로 유용한 경우입니다. rel에는 자식 sequel이 있고 모든 간선이 sequel로
만들어졌으므로, rel ONLY는 그중 하나도 일치시키지 못하지만 그냥 rel은 전부 일치시킵니다.
간선도 같은 방식으로 상속한다#
CREATE ELABEL rel;
CREATE ELABEL sequel INHERITS (rel);
MATCH (a:film {title: 'A'}), (b:series {title: 'B'}) CREATE (a)-[:sequel]->(b);
MATCH ()-[e:rel]->() RETURN label(e) AS label;
label
----------
"sequel"
부모가 둘 이상일 때#
레이블은 여러 레이블을 한 번에 상속할 수 있습니다:
CREATE VLABEL hybrid INHERITS (work, film);
그러면 hybrid의 행은 MATCH (n:work)에도 일치하고 MATCH (n:film)에도 일치합니다.
모든 그래프가 이미 상속하고 있는 것#
직접 만드는 모든 레이블은 INHERITS 절을 쓰지 않아도 ag_vertex나 ag_edge를 상속합니다.
레이블 없는 MATCH (n)이 모든 것에 일치하는 이유가 그것입니다.
그래프가 어떻게 저장되는가를
참고하십시오.
비용은 무엇인가#
부모에 대한 패턴은 부모의 테이블과 그 아래 모든 테이블을 스캔하므로, 실행 계획에 계열 전체를 훑는
Append가 붙습니다:
EXPLAIN (COSTS OFF) MATCH (n:work) RETURN n;
QUERY PLAN
------------------------------------
Result
-> Append
-> Seq Scan on work n_1
-> Seq Scan on film n_2
-> Seq Scan on series n_3
-> Seq Scan on hybrid n_4
ONLY는 그 Append를 없앱니다:
EXPLAIN (COSTS OFF) MATCH (n:work ONLY) RETURN n;
QUERY PLAN
--------------------
Seq Scan on work n
여기서 두 가지가 따라옵니다. 계층이 깊으면, “한 레이블의 행을 달라”는 가장 값싼 쿼리조차 필요보다
많은 관계에 대해 계획을 세우게 됩니다. 그러므로 한 레이블의 행만 원한다면 자식을 이름으로 부르거나
ONLY를 붙이십시오. 그리고 인덱스는 스캔될 테이블마다 있어야 합니다. work에 걸린 인덱스가
film의 행을 인덱싱해 주지는 않습니다. 계층 전체에 인덱스를 만드는 방법은
인덱스와 제약이 다룹니다.
참고
쿼리가 정말로 계열 전체를 원할 때 상속을 꺼내십시오 — 어떤 때는 film이고 어떤 때는 series인
work 같은 경우입니다. 어차피 모든 쿼리가 자식을 이름으로 부른다면, 레이블을 따로 두는 편이 더
단순하고 계획도 더 잘 나옵니다.