{#create-elabel-create-elabel} # CREATE ELABEL 간선 레이블을 만듭니다. 그래프의 기반 간선 레이블을 상속하는 `(id, start, end, properties)` 테이블이며, 속성을 타입 컬럼으로 승격할 수도 있습니다. {#create-elabel-synopsis} ## 개요
CREATE [ UNLOGGED ] ELABEL [ IF NOT EXISTS ] label_name [ ( promoted_property [, ... ] ) ]
    [ 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 ]

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

{#create-elabel-description} ## 설명 간선 레이블은 컬럼 네 개를 가진 테이블입니다. `graphid` 타입의 `id`, 간선의 `start`·`end` 정점의 `graphid`, 그리고 `jsonb` 타입의 `properties` 컬럼입니다. 부모를 지정하지 않으면 그래프의 `ag_edge`를 상속합니다. 간선 레이블을 만들면 그 id에 번호를 매기는 시퀀스와 인덱스 세 개도 함께 만들어집니다. 둘은 `(start, "end")`와 `("end", start)`에 걸린 btree 인덱스이고, 그것이 순회를 어느 방향으로든 빠르게 만들어 줍니다. 셋째는 `id`에 걸린 BRIN 인덱스입니다. 간선 레이블에는 `id`에 대한 기본 키가 생기지 않습니다. 간선은 양 끝점을 통해 도달하기 때문입니다. 그 배치는 [그래프가 어떻게 저장되는가](../../concepts/graph-on-postgresql.md)가 다룹니다. 레이블은 `graph_path`가 지정한 그래프에 만들어집니다. - **옵션은 순서가 중요합니다.** 보인 순서대로 와야 합니다. `DISABLE INDEX`, 그다음 `INHERITS`, 그다음 `WITH`, 그다음 `TABLESPACE`입니다. 다른 순서는 구문 오류입니다. - `INHERITS`에 지정한 부모는 같은 그래프에 있어야 하고 간선 레이블이어야 합니다. 정점 레이블을 지정하면 거부됩니다. - `IF NOT EXISTS`와 `ONLY`는 서로 다른 형태에 속하므로 함께 쓸 수 없습니다. - 간선 레이블은 양 끝점이 어떤 레이블이어야 하는지 제한하지 않습니다. `start`와 `end`는 외래 키가 아니라 평범한 `graphid` 컬럼입니다. - Cypher는 필요할 때 레이블을 만듭니다. `directed` 레이블이 없는 그래프에 `CREATE (a)-[:directed]->(b)`를 쓰면 그 레이블이 만들어집니다. 옵션, 승격 컬럼, 부모가 필요할 때 `CREATE ELABEL`을 쓰십시오. {#create-elabel-promoted-properties} ### 승격된 속성 승격된 속성은 `properties` 옆에 있는 타입 컬럼이며, `properties`에서 계산해 저장한 것입니다. 그 속성을 읽으면 JSON 문서 안이 아니라 그 컬럼으로 갑니다. 세 형태와 그 제한은 정점 레이블과 같고, [`CREATE VLABEL`](#create-vlabel-promoted-properties)이 그것을 설명합니다. 간선 레이블에서 예약된 컬럼 이름은 `id`, `properties`, `start`, `end`입니다. {#create-elabel-parameters} ## 매개변수 UNLOGGED : 레이블의 테이블을 unlogged로 만듭니다. 그 내용은 미리 쓰기 로그에 기록되지 않으며 비정상 종료 뒤에는 사라집니다. IF NOT EXISTS : 그 이름의 레이블이 이미 있을 때 오류가 아니라 알림을 냅니다. 아무것도 만들어지지 않고, 이미 있는 레이블의 옵션도 바뀌지 않습니다. label_name : 만들 레이블의 이름이며, `graph_path`가 지정한 그래프 안에 만듭니다. promoted_property : 타입 컬럼으로 함께 비출 속성입니다. 컬럼은 적은 순서대로 `properties` 뒤에 추가됩니다. DISABLE INDEX : 레이블의 인덱스 세 개를 만들되 무효 상태로 두어, 행을 적재할 때 그것을 유지하지 않게 합니다. 읽기와 쓰기는 그대로 동작하고, 플래너는 무효 인덱스를 무시합니다. 다시 만들 때는 [`REINDEX ELABEL`](reindex.md)을 쓰십시오. `ENABLE INDEX`는 없습니다. INHERITS ( parent_label [, ...] ) : 기본 부모인 `ag_edge`를 대신하는 부모 레이블입니다. 각각 같은 그래프의 간선 레이블이어야 합니다. [레이블 상속](../../concepts/label-inheritance.md)을 참고하십시오. WITH ( storage_parameter [= value] [, ...] ) : `CREATE TABLE`에서와 같이, 레이블 테이블의 저장 매개변수입니다. TABLESPACE tablespace_name : 레이블 테이블의 테이블스페이스입니다. 이것이 없으면 `default_tablespace`가 결정합니다. ONLY label_name ( label_id ) : 주어진 레이블 id로, 기본 부모·id 기본값·끝점 인덱스 없이 레이블을 만듭니다. 덤프한 그래프의 id를 복원이 보존할 수 있도록 `pg_dump`가 내보내는 형태입니다. 덤프를 재현할 때만 쓰십시오. {#create-elabel-examples} ## 예제 예제는 [예제 데이터셋](../../get_started/example-dataset.md)을 쓰지 않고 자체 그래프인 `castlists`를 만들고, 끝에서 그것을 지웁니다. {#create-elabel-create-an-edge-label} ### 간선 레이블 만들기 ```cypher CREATE GRAPH castlists; SET graph_path = castlists; CREATE VLABEL person; CREATE VLABEL film; CREATE ELABEL worked_on; ``` ``` CREATE ELABEL ``` ```psql \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으로 설정됐습니다. 순회의 행 추정이 그 두 컬럼의 분포에 달려 있기 때문입니다: ```sql 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-group-several-edge-types-under-one-parent} ### 여러 간선 종류를 한 부모 아래로 묶기 ```cypher CREATE ELABEL acted_in INHERITS (worked_on); CREATE ELABEL directed INHERITS (worked_on); ``` ```psql \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()`은 여전히 그 간선이 만들어질 때의 레이블을 보고합니다: ```cypher 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-create-a-label-only-if-it-is-not-there} ### 없을 때만 레이블 만들기 ```cypher CREATE ELABEL IF NOT EXISTS acted_in; ``` ``` NOTICE: label "acted_in" already exists, skipping CREATE ELABEL ``` {#create-elabel-load-an-edge-label-before-building-its-indexes} ### 인덱스를 만들기 전에 간선 레이블 적재하기 인덱스 세 개가 모두 무효 상태로 만들어지고, 테이블 자체는 unlogged입니다: ```cypher CREATE UNLOGGED ELABEL staged DISABLE INDEX WITH (fillfactor = 70) TABLESPACE pg_default; ``` ```psql \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-promote-an-edge-property-to-a-typed-column} ### 간선 속성을 타입 컬럼으로 승격하기 ```cypher CREATE ELABEL scored (rating numeric GENERATED, source text GENERATED (site)); ``` ```psql \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 ``` 간선을 쓰면 두 컬럼이 모두 채워집니다: ```cypher MATCH (p:person), (f:film) CREATE (p)-[:scored {rating: 8.5, site: 'critics'}]->(f); ``` ``` UPDATE 1 ``` SQL은 그것을 컬럼 이름으로 읽습니다: ```sql SELECT rating, source FROM castlists.scored; ``` ``` rating | source --------+--------- 8.5 | critics (1 row) ``` Cypher는 그것을 속성 키로 읽으므로, 두 번째 것은 `e.source`가 아니라 `e.site`입니다: ```cypher MATCH ()-[e:scored]->() RETURN e.rating AS rating, e.site AS site; ``` ``` rating | site --------+--------- 8.5 | critics (1 row) ``` {#create-elabel-refusals-worth-recognizing} ### 알아 둘 만한 거부 사례 간선 레이블은 간선 레이블만 상속할 수 있습니다: ```cypher CREATE ELABEL wrong INHERITS (person); ``` ``` ERROR: parent graph label "person" is not edge label. ``` 마지막으로 예제가 만든 그래프를 지웁니다: ```cypher DROP GRAPH castlists CASCADE; ``` {#create-elabel-notes} ## 참고 레이블 이름은 수식할 수 없습니다. `CREATE ELABEL castlists.directed`는 구문 오류이고, 그래프는 항상 `graph_path`에서 옵니다. 설정된 것이 없으면 이 문장은 `graph_path is NULL`로 멈춥니다. `\dGe`는 간선 레이블을 나열하고 일치하는 것마다 설명해 줍니다. `\dGl`은 두 종류의 레이블을 자세한 설명 없이 나열합니다. {#create-elabel-compatibility} ## 호환성 {#create-elabel-isoiec-39075-gql} ### ISO/IEC 39075 (GQL) GQL에는 레이블 DDL이 없습니다. 간선은 그래프 타입 안의 *간선 타입*으로 기술되며, ``(§12.6)에 해당합니다. 간선 타입은 그 간선의 끝점 정점 타입과 속성을 지정하고, 그것을 참조하는 그래프를 제약합니다. AgensGraph는 간선 레이블을 하나씩 선언하고, 간선 레이블은 자기 끝점도 속성도 제약하지 않습니다. 그래프 타입은 [GQL 적합성 표](../../appendix/gql-conformance.md)에 계획으로 기록돼 있습니다. {#create-elabel-postgresql} ### PostgreSQL `CREATE ELABEL`은 `CREATE TABLE`에 대응합니다. `UNLOGGED`, `IF NOT EXISTS`, `INHERITS`, `WITH`, `TABLESPACE`는 거기서와 같은 뜻이고, 승격 속성 형태는 `GENERATED ALWAYS AS ... STORED` 생성 컬럼이 됩니다. 다른 점은 고정된 네 컬럼 모양, 함께 만들어지는 인덱스 세 개, `ag_label` 등록, 자동으로 붙는 부모, 그리고 순서가 중요한 옵션 배치입니다. `start`와 `end`는 외래 키로 선언되지 않으므로, 테이블 수준에서는 간선이 이미 지워진 정점을 가리키는 것을 막는 것이 없습니다. 그 일은 [`DROP VLABEL`](drop-label.md)이 처리합니다. {#create-elabel-see-also} ## 관련 항목 - [`CREATE VLABEL`](create-vlabel.md) - [`ALTER VLABEL`·`ALTER ELABEL`](alter-label.md) - [`DROP VLABEL`·`DROP ELABEL`](drop-label.md) - [`REINDEX VLABEL`·`REINDEX ELABEL`](reindex.md) - [레이블 상속](../../concepts/label-inheritance.md)