CREATE ELABEL#
간선 레이블을 만듭니다. 그래프의 기반 간선 레이블을 상속하는 (id, start, end, properties) 테이블이며,
속성을 타입 컬럼으로 승격할 수도 있습니다.
개요#
[ DISABLE INDEX ]
[ INHERITS ( parent_label [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ TABLESPACE tablespace_name ]
CREATE [ UNLOGGED ] ELABEL ONLY label_name ( label_id ) [ option ... ]
where promoted_property is one of:
column_name data_type GENERATED
column_name data_type GENERATED ( property_key )
column_name data_type GENERATED ALWAYS AS ( expression ) [ STORED ]
굵게 키워드 · 기울임 직접 채우는 자리 · [ ] 생략 가능 · ... 반복 가능. 구문 표기 규약을 참고하십시오.
설명#
간선 레이블은 컬럼 네 개를 가진 테이블입니다. graphid 타입의 id, 간선의 start·end 정점의
graphid, 그리고 jsonb 타입의 properties 컬럼입니다. 부모를 지정하지 않으면 그래프의
ag_edge를 상속합니다.
간선 레이블을 만들면 그 id에 번호를 매기는 시퀀스와 인덱스 세 개도 함께 만들어집니다. 둘은
(start, "end")와 ("end", start)에 걸린 btree 인덱스이고, 그것이 순회를 어느 방향으로든 빠르게
만들어 줍니다. 셋째는 id에 걸린 BRIN 인덱스입니다. 간선 레이블에는 id에 대한 기본 키가 생기지
않습니다. 간선은 양 끝점을 통해 도달하기 때문입니다. 그 배치는
그래프가 어떻게 저장되는가가 다룹니다.
레이블은 graph_path가 지정한 그래프에 만들어집니다.
옵션은 순서가 중요합니다. 보인 순서대로 와야 합니다.
DISABLE INDEX, 그다음INHERITS, 그다음WITH, 그다음TABLESPACE입니다. 다른 순서는 구문 오류입니다.INHERITS에 지정한 부모는 같은 그래프에 있어야 하고 간선 레이블이어야 합니다. 정점 레이블을 지정하면 거부됩니다.IF NOT EXISTS와ONLY는 서로 다른 형태에 속하므로 함께 쓸 수 없습니다.간선 레이블은 양 끝점이 어떤 레이블이어야 하는지 제한하지 않습니다.
start와end는 외래 키가 아니라 평범한graphid컬럼입니다.Cypher는 필요할 때 레이블을 만듭니다.
directed레이블이 없는 그래프에CREATE (a)-[:directed]->(b)를 쓰면 그 레이블이 만들어집니다. 옵션, 승격 컬럼, 부모가 필요할 때CREATE ELABEL을 쓰십시오.
승격된 속성#
승격된 속성은 properties 옆에 있는 타입 컬럼이며, properties에서 계산해 저장한 것입니다.
그 속성을 읽으면 JSON 문서 안이 아니라 그 컬럼으로 갑니다. 세 형태와 그 제한은 정점 레이블과 같고,
CREATE VLABEL이 그것을 설명합니다. 간선 레이블에서 예약된
컬럼 이름은 id, properties, start, end입니다.
매개변수#
- UNLOGGED
레이블의 테이블을 unlogged로 만듭니다. 그 내용은 미리 쓰기 로그에 기록되지 않으며 비정상 종료 뒤에는 사라집니다.
- IF NOT EXISTS
그 이름의 레이블이 이미 있을 때 오류가 아니라 알림을 냅니다. 아무것도 만들어지지 않고, 이미 있는 레이블의 옵션도 바뀌지 않습니다.
- label_name
만들 레이블의 이름이며,
graph_path가 지정한 그래프 안에 만듭니다.- promoted_property
타입 컬럼으로 함께 비출 속성입니다. 컬럼은 적은 순서대로
properties뒤에 추가됩니다.- DISABLE INDEX
레이블의 인덱스 세 개를 만들되 무효 상태로 두어, 행을 적재할 때 그것을 유지하지 않게 합니다. 읽기와 쓰기는 그대로 동작하고, 플래너는 무효 인덱스를 무시합니다. 다시 만들 때는
REINDEX ELABEL을 쓰십시오.ENABLE INDEX는 없습니다.- INHERITS ( parent_label [, …] )
기본 부모인
ag_edge를 대신하는 부모 레이블입니다. 각각 같은 그래프의 간선 레이블이어야 합니다. 레이블 상속을 참고하십시오.- WITH ( storage_parameter [= value] [, …] )
CREATE TABLE에서와 같이, 레이블 테이블의 저장 매개변수입니다.- TABLESPACE tablespace_name
레이블 테이블의 테이블스페이스입니다. 이것이 없으면
default_tablespace가 결정합니다.- ONLY label_name ( label_id )
주어진 레이블 id로, 기본 부모·id 기본값·끝점 인덱스 없이 레이블을 만듭니다. 덤프한 그래프의 id를 복원이 보존할 수 있도록
pg_dump가 내보내는 형태입니다. 덤프를 재현할 때만 쓰십시오.
예제#
예제는 예제 데이터셋을 쓰지 않고 자체 그래프인
castlists를 만들고, 끝에서 그것을 지웁니다.
간선 레이블 만들기#
CREATE GRAPH castlists;
SET graph_path = castlists;
CREATE VLABEL person;
CREATE VLABEL film;
CREATE ELABEL worked_on;
CREATE ELABEL
\d castlists.worked_on
Table "castlists.worked_on"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-------------------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('castlists.worked_on'::cstring), nextval('castlists.worked_on_id_seq'::regclass))
start | graphid | | not null |
end | graphid | | not null |
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"worked_on_end_idx" btree ("end", start)
"worked_on_id_idx" brin (id)
"worked_on_start_idx" btree (start, "end")
Inherits: castlists.ag_edge
레이블을 만들 때 start와 end의 통계 목표도 1000으로 설정됐습니다. 순회의 행 추정이 그 두 컬럼의
분포에 달려 있기 때문입니다:
SELECT attname, attstattarget FROM pg_attribute
WHERE attrelid = 'castlists.worked_on'::regclass AND attnum > 0;
attname | attstattarget
------------+---------------
id |
start | 1000
end | 1000
properties |
(4 rows)
여러 간선 종류를 한 부모 아래로 묶기#
CREATE ELABEL acted_in INHERITS (worked_on);
CREATE ELABEL directed INHERITS (worked_on);
\dGe castlists.acted_in
List of labels
Graph | Name | Type | Owner
-----------+----------+------+-------
castlists | acted_in | edge | agens
(1 row)
Edge label "castlists.acted_in"
--
Inherits: castlists.worked_on
이제 부모에 대한 패턴이 두 종류의 간선 모두에 일치하고, label()은 여전히 그 간선이 만들어질 때의
레이블을 보고합니다:
CREATE (:person {name: 'Denis Villeneuve'})-[:directed {credited: true}]->(:film {title: 'Arrival'});
MATCH (p)-[e:worked_on]->(f) RETURN label(e) AS type, e.credited AS credited;
type | credited
------------+----------
"directed" | true
(1 row)
없을 때만 레이블 만들기#
CREATE ELABEL IF NOT EXISTS acted_in;
NOTICE: label "acted_in" already exists, skipping
CREATE ELABEL
인덱스를 만들기 전에 간선 레이블 적재하기#
인덱스 세 개가 모두 무효 상태로 만들어지고, 테이블 자체는 unlogged입니다:
CREATE UNLOGGED ELABEL staged DISABLE INDEX WITH (fillfactor = 70) TABLESPACE pg_default;
\d castlists.staged
Unlogged table "castlists.staged"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-------------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('castlists.staged'::cstring), nextval('castlists.staged_id_seq'::regclass))
start | graphid | | not null |
end | graphid | | not null |
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"staged_end_idx" btree ("end", start) INVALID
"staged_id_idx" brin (id) INVALID
"staged_start_idx" btree (start, "end") INVALID
Inherits: castlists.ag_edge
간선을 적재하고, 그다음 REINDEX ELABEL staged를 실행해 인덱스 세 개를 만드십시오.
간선 속성을 타입 컬럼으로 승격하기#
CREATE ELABEL scored (rating numeric GENERATED, source text GENERATED (site));
\d castlists.scored
Table "castlists.scored"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-------------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('castlists.scored'::cstring), nextval('castlists.scored_id_seq'::regclass))
start | graphid | | not null |
end | graphid | | not null |
properties | jsonb | | not null | jsonb_build_object()
rating | numeric | | | generated always as (ag_property_text(properties, 'rating'::text, 'n'::"char")::numeric) stored
source | text | | | generated always as (ag_property_text(properties, 'site'::text, 's'::"char")) stored
Indexes:
"scored_end_idx" btree ("end", start)
"scored_id_idx" brin (id)
"scored_start_idx" btree (start, "end")
Inherits: castlists.ag_edge
간선을 쓰면 두 컬럼이 모두 채워집니다:
MATCH (p:person), (f:film) CREATE (p)-[:scored {rating: 8.5, site: 'critics'}]->(f);
UPDATE 1
SQL은 그것을 컬럼 이름으로 읽습니다:
SELECT rating, source FROM castlists.scored;
rating | source
--------+---------
8.5 | critics
(1 row)
Cypher는 그것을 속성 키로 읽으므로, 두 번째 것은 e.source가 아니라 e.site입니다:
MATCH ()-[e:scored]->() RETURN e.rating AS rating, e.site AS site;
rating | site
--------+---------
8.5 | critics
(1 row)
알아 둘 만한 거부 사례#
간선 레이블은 간선 레이블만 상속할 수 있습니다:
CREATE ELABEL wrong INHERITS (person);
ERROR: parent graph label "person" is not edge label.
마지막으로 예제가 만든 그래프를 지웁니다:
DROP GRAPH castlists CASCADE;
참고#
레이블 이름은 수식할 수 없습니다. CREATE ELABEL castlists.directed는 구문 오류이고, 그래프는 항상
graph_path에서 옵니다. 설정된 것이 없으면 이 문장은 graph_path is NULL로 멈춥니다.
\dGe는 간선 레이블을 나열하고 일치하는 것마다 설명해 줍니다. \dGl은 두 종류의 레이블을 자세한
설명 없이 나열합니다.
호환성#
ISO/IEC 39075 (GQL)#
GQL에는 레이블 DDL이 없습니다. 간선은 그래프 타입 안의 간선 타입으로 기술되며,
<create graph type statement>(§12.6)에 해당합니다. 간선 타입은 그 간선의 끝점 정점 타입과 속성을
지정하고, 그것을 참조하는 그래프를 제약합니다. AgensGraph는 간선 레이블을 하나씩 선언하고, 간선
레이블은 자기 끝점도 속성도 제약하지 않습니다. 그래프 타입은
GQL 적합성 표에 계획으로 기록돼 있습니다.
PostgreSQL#
CREATE ELABEL은 CREATE TABLE에 대응합니다. UNLOGGED, IF NOT EXISTS, INHERITS, WITH,
TABLESPACE는 거기서와 같은 뜻이고, 승격 속성 형태는 GENERATED ALWAYS AS ... STORED 생성 컬럼이
됩니다. 다른 점은 고정된 네 컬럼 모양, 함께 만들어지는 인덱스 세 개, ag_label 등록, 자동으로
붙는 부모, 그리고 순서가 중요한 옵션 배치입니다. start와 end는 외래 키로 선언되지 않으므로,
테이블 수준에서는 간선이 이미 지워진 정점을 가리키는 것을 막는 것이 없습니다. 그 일은
DROP VLABEL이 처리합니다.