CREATE VLABEL#
정점 레이블을 만듭니다. 그래프의 기반 정점 레이블을 상속하는 (id, properties) 테이블이며, 속성을
타입 컬럼으로 승격할 수도 있습니다.
개요#
[ DISABLE INDEX ]
[ INHERITS ( parent_label [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ TABLESPACE tablespace_name ]
CREATE [ UNLOGGED ] VLABEL 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와 jsonb 타입의 properties 컬럼을 가진 테이블입니다. 부모를
지정하지 않으면 그래프의 ag_vertex를 상속합니다. 정점 레이블을 만들면 그 id에 번호를 매기는
시퀀스와 id에 대한 기본 키도 함께 만들어집니다. 그 배치는
그래프가 어떻게 저장되는가가 다룹니다.
레이블은 graph_path가 지정한 그래프에 만들어집니다.
옵션은 순서가 중요합니다. 보인 순서대로 와야 합니다.
DISABLE INDEX, 그다음INHERITS, 그다음WITH, 그다음TABLESPACE입니다. 다른 순서는 구문 오류입니다.INHERITS에 지정한 부모는 같은 그래프에 있어야 하고 정점 레이블이어야 합니다.IF NOT EXISTS와ONLY는 서로 다른 형태에 속하므로 함께 쓸 수 없습니다.Cypher는 필요할 때 레이블을 만듭니다.
film레이블이 없는 그래프에CREATE (:film)을 쓰면 그 레이블이 만들어집니다. 옵션, 승격 컬럼, 부모가 필요할 때CREATE VLABEL을 쓰십시오.
승격된 속성#
승격된 속성은 properties 옆에 있는 실제 타입 컬럼이며, properties에서 계산해 저장한
것입니다. 그 속성을 읽으면 JSON 문서를 훑는 대신 그 컬럼으로 갑니다. 세 형태는 값이 어디서
오는지가 다릅니다:
column_name data_type GENERATED는 키가 그 컬럼 이름인 속성을 비춥니다.column_name data_type GENERATED ( property_key )는 지정한 키를 비추므로, 컬럼 이름을 다르게 붙일 수 있습니다. 그 키는 식별자여서 소문자로 내려가며, Cypher가 맵 키를 저장하는 방식과 같습니다.column_name data_type GENERATED ALWAYS AS ( expression ) STORED는 그 레이블 자신의 컬럼에 대한 SQL 표현식으로 컬럼을 계산합니다.
어떤 컬럼이 속성을 대신해 답하는지는 어느 형태로 썼는지가 아니라 그 표현식이 결정합니다. 형 변환을
붙이든 붙이지 않든 properties ->> 'year'처럼 properties에서 키 하나를 그냥 읽는 것은
ag_label_property에 기록됩니다. Cypher의 속성 읽기가 참조하는 카탈로그가 그것입니다. 그 읽기를
다른 무엇으로 감싸면 그 컬럼은 평범한 생성 컬럼이 됩니다. SQL은 그것을 읽고, n.<key>는 그것을
보지 못합니다. 승격이 언제 할 만한지는
속성을 컬럼으로 승격하기가 설명합니다.
승격된 속성이 될 수 없는 것 네 가지입니다:
생성 컬럼이 아닌 것.
column_name data_type만 쓰면a non-generated promoted column is not supported yet로 거부됩니다.VIRTUAL. 승격 컬럼은 인덱스를 지니려면 구체화돼야 하므로,VIRTUAL은promoted generated properties must be STORED로 거부됩니다.STORED가 기본값이며 생략할 수 있습니다.GENERATED BY DEFAULT.GENERATED ALWAYS만 받아들여집니다.id·properties·start·end라는 이름. 그것들은 그래프 요소의 구조 컬럼이므로, 그 이름은 예약된 것으로 거부됩니다.
데이터 타입은 텍스트 입력 함수가 불변인 타입이어야 하고, 길이를 고정할 수 없습니다. date,
timestamp, timestamptz와 배열 타입은 generation expression is not immutable로 거부됩니다.
varchar(n)과 char(n)은 값을 길이에 맞추는 과정에서 컬럼과 속성이 서로 다른 값을 담게 될 수
있으므로 거부됩니다. smallint, int, bigint, numeric, real, double precision, text,
boolean, uuid, jsonb는 받아들여집니다.
매개변수#
- UNLOGGED
레이블의 테이블을 unlogged로 만듭니다. 그 내용은 미리 쓰기 로그에 기록되지 않으며 비정상 종료 뒤에는 사라집니다.
- IF NOT EXISTS
그 이름의 레이블이 이미 있을 때 오류가 아니라 알림을 냅니다. 아무것도 만들어지지 않고, 이미 있는 레이블의 옵션도 바뀌지 않습니다.
- label_name
만들 레이블의 이름이며,
graph_path가 지정한 그래프 안에 만듭니다.- promoted_property
위 세 형태 중 하나로, 타입 컬럼으로 함께 비출 속성입니다. 컬럼은 적은 순서대로
properties뒤에 추가됩니다.- DISABLE INDEX
레이블의 인덱스를 만들되 무효 상태로 두어, 행을 적재할 때 그것을 유지하지 않게 합니다. 읽기와 쓰기는 그대로 동작하고, 플래너는 무효 인덱스를 무시합니다. 다시 만들 때는
REINDEX VLABEL을 쓰십시오.ENABLE INDEX는 없습니다.- INHERITS ( parent_label [, …] )
기본 부모인
ag_vertex를 대신하는 부모 레이블입니다. 각각 같은 그래프의 정점 레이블이어야 합니다. 레이블 상속을 참고하십시오.- WITH ( storage_parameter [= value] [, …] )
CREATE TABLE에서와 같이, 레이블 테이블의 저장 매개변수입니다.- TABLESPACE tablespace_name
레이블 테이블의 테이블스페이스입니다. 이것이 없으면
default_tablespace가 결정합니다.- ONLY label_name ( label_id )
주어진 레이블 id로, 기본 부모·id 기본값·기본 키 없이 레이블을 만듭니다. 그 레이블 id는 이 레이블이 내주는 모든
graphid의 상위 16비트입니다. 덤프한 그래프의 id를 복원이 보존할 수 있도록pg_dump가 내보내는 형태입니다. 이렇게 만든 레이블은 그것들을 되돌려 놓기 전까지 Cypher에서 쓸 수 없으므로, 덤프를 재현할 때만 쓰십시오.
예제#
예제는 예제 데이터셋을 쓰지 않고 자체 그래프인
filmstore를 만들고, 끝에서 그것을 지웁니다.
정점 레이블 만들기#
CREATE GRAPH filmstore;
SET graph_path = filmstore;
CREATE VLABEL film;
CREATE VLABEL
\d filmstore.film
Table "filmstore.film"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+---------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('filmstore.film'::cstring), nextval('filmstore.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"film_pkey" PRIMARY KEY, btree (id)
Inherits: filmstore.ag_vertex
없을 때만 레이블 만들기#
CREATE VLABEL IF NOT EXISTS film;
NOTICE: label "film" already exists, skipping
CREATE VLABEL
부모 아래에 레이블 만들기#
CREATE VLABEL work;
CREATE VLABEL documentary INHERITS (work);
\dGv filmstore.documentary
List of labels
Graph | Name | Type | Owner
-----------+-------------+--------+-------
filmstore | documentary | vertex | agens
(1 row)
Vertex label "filmstore.documentary"
--
Inherits: filmstore.work
documentary는 ag_vertex 대신 work를 상속하므로 MATCH (n:work)가 다큐멘터리에도 일치합니다.
나머지는 레이블 상속이 다룹니다.
인덱스를 만들기 전에 레이블 적재하기#
CREATE VLABEL bulk DISABLE INDEX;
\d filmstore.bulk
Table "filmstore.bulk"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+---------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('filmstore.bulk'::cstring), nextval('filmstore.bulk_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"bulk_pkey" PRIMARY KEY, btree (id) INVALID
Inherits: filmstore.ag_vertex
기본 키는 존재하지만 INVALID로 표시됩니다. 행을 적재하고, 그다음 REINDEX VLABEL bulk를 실행해
그것을 만드십시오.
저장 매개변수와 테이블스페이스 설정하기#
CREATE UNLOGGED VLABEL staging WITH (fillfactor = 70) TABLESPACE pg_default;
SELECT relpersistence, reloptions FROM pg_class WHERE oid = 'filmstore.staging'::regclass;
relpersistence | reloptions
----------------+-----------------
u | {fillfactor=70}
(1 row)
속성 두 개를 타입 컬럼으로 승격하기#
CREATE VLABEL title (year int GENERATED, name text GENERATED);
\d filmstore.title
Table "filmstore.title"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('filmstore.title'::cstring), nextval('filmstore.title_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
year | integer | | | generated always as (ag_property_text(properties, 'year'::text, 'n'::"char")::integer) stored
name | text | | | generated always as (ag_property_text(properties, 'name'::text, 's'::"char")) stored
Indexes:
"title_pkey" PRIMARY KEY, btree (id)
Inherits: filmstore.ag_vertex
쓰기에 관해 바뀌는 것은 없습니다. 속성은 여전히 properties로 들어가고, 컬럼이 그것을 따라갑니다:
CREATE (:title {name: 'Arrival', year: 2016});
MATCH (t:title) RETURN t.name AS name, t.year AS year;
name | year
---------+------
Arrival | 2016
(1 row)
같은 값이 컬럼에도 있고, SQL에서 닿을 수 있습니다:
SELECT name, year FROM filmstore.title;
name | year
---------+------
Arrival | 2016
(1 row)
값이 그 컬럼의 종류와 맞지 않는 속성은 쓰기 시점에 거부되며, 양쪽을 모두 이름으로 알려 줍니다:
CREATE (:title {name: 42, year: 2016});
ERROR: property "name" holds a number
DETAIL: A column promoting this property holds strings.
CONTEXT: while computing the promoted typed columns of graph label "title"
키가 컬럼 이름과 다른 속성 승격하기#
CREATE VLABEL review (released text GENERATED (releaseDate));
\d filmstore.review
Table "filmstore.review"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-------------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('filmstore.review'::cstring), nextval('filmstore.review_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
released | text | | | generated always as (ag_property_text(properties, 'releasedate'::text, 's'::"char")) stored
Indexes:
"review_pkey" PRIMARY KEY, btree (id)
Inherits: filmstore.ag_vertex
키를 releaseDate로 적었지만 releasedate로 저장됐습니다. 여기서 속성 키는 식별자이고 식별자는
소문자로 내려가기 때문입니다. Cypher는 이 속성을 n.releasedate로 읽고, SQL은 그 컬럼을
released로 읽습니다.
properties에서 컬럼 계산하기#
긴 형태는 속성 키가 아니라 그 레이블 자신의 컬럼에 대한 SQL 표현식을 받습니다:
CREATE VLABEL slug (handle text GENERATED ALWAYS AS (lower(properties ->> 'name')) STORED);
\d filmstore.slug
Table "filmstore.slug"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+---------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('filmstore.slug'::cstring), nextval('filmstore.slug_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
handle | text | | | generated always as (lower(properties ->> 'name'::text)) stored
Indexes:
"slug_pkey" PRIMARY KEY, btree (id)
Inherits: filmstore.ag_vertex
CREATE (:slug {name: 'Arrival'});
UPDATE 1
Cypher 쓰기는 그 쓰기가 무엇이었든 행 수를 UPDATE 태그로 보고하고, 그 컬럼은 계산되어
저장됩니다:
SELECT handle FROM filmstore.slug;
handle
---------
arrival
(1 row)
그러나 어떤 속성 키에도 답하지 않으므로 Cypher는 그것을 보지 못합니다:
MATCH (s:slug) RETURN s.handle AS handle;
handle
--------
(1 row)
s.handle은 properties에서 handle 키를 읽는데, 그것을 쓴 것은 아무것도 없습니다.
표현식이 키 하나를 그냥 읽는 것인 긴 형태는 축약형처럼 기록되고, Cypher도 그것을 봅니다:
CREATE VLABEL runtime (minutes int GENERATED ALWAYS AS ((properties ->> 'minutes')::int) STORED);
CREATE (:runtime {minutes: 116});
MATCH (r:runtime) RETURN r.minutes AS minutes;
minutes
---------
116
(1 row)
그러므로 그 컬럼이 어떤 속성을 대신해 답해야 한다면 키 하나를 꺼내 쓰고, 그 컬럼이 SQL만을 위한 것이라면 계산해 쓰십시오.
알아 둘 만한 거부 사례#
아래는 모두 그대로 거부됩니다:
CREATE VLABEL bad1 (name varchar(40) GENERATED);
ERROR: a promoted property cannot have a length-limited string type
DETAIL: Type character varying fits a value to its length by truncating or padding it.
HINT: Use text, which stores the property as it is.
CREATE VLABEL bad2 (name text);
ERROR: a non-generated promoted column is not supported yet
HINT: Use GENERATED to mirror the property from the jsonb bag.
CREATE VLABEL bad3 (released date GENERATED);
ERROR: generation expression is not immutable
CREATE VLABEL bad4 (id int GENERATED);
ERROR: promoted property name "id" is reserved
CREATE VLABEL bad5 (name text GENERATED ALWAYS AS (properties ->> 'name') VIRTUAL);
ERROR: promoted generated properties must be STORED
LINE 1: ...e text GENERATED ALWAYS AS (properties ->> 'name') VIRTUAL);
^
HINT: A VIRTUAL generated column cannot carry an index.
속성 키는 계층 전체에서 하나의 컬럼으로 이어져야 합니다. 그래서 부모가 이미 승격한 키를 승격하는 것은 컬럼 이름이 같지 않으면 거부됩니다:
CREATE VLABEL feature (year int GENERATED) INHERITS (work);
CREATE VLABEL short (released int GENERATED (year)) INHERITS (feature);
ERROR: property "year" is already promoted on graph label "feature"
DETAIL: It answers from column "year" there and would answer from column "released" here.
HINT: Promote it to the same column name, or leave it to the label that has it.
반대 경우도 거부됩니다. 조상이 이미 쓰는 컬럼 이름으로 다른 키를 승격하면, 키 둘이 상속된 컬럼 하나를 읽게 됩니다.
주어진 레이블 id로 레이블 다시 만들기#
레이블 id는 그래프의 ag_label_seq에서 만들어진 순서대로 나옵니다. ONLY는 그것을 명시적으로
정하며, 복원이 덤프에 담긴 id를 재현하는 방법이 그것입니다:
CREATE VLABEL ONLY restored (300);
SELECT l.labname, l.labid FROM pg_catalog.ag_label l
JOIN pg_catalog.ag_graph g ON g.oid = l.graphid
WHERE g.graphname = 'filmstore' ORDER BY l.labid;
labname | labid
-------------+-------
ag_vertex | 1
ag_edge | 2
film | 3
work | 4
documentary | 5
bulk | 6
staging | 7
title | 8
review | 9
slug | 10
runtime | 11
feature | 12
restored | 300
(13 rows)
그 레이블에는 부모도, id 기본값도, 기본 키도 없습니다. 그래서 그 상태로는 Cypher에서 쓸 수
없습니다:
\d filmstore.restored
Table "filmstore.restored"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+---------
id | graphid | | not null |
properties | jsonb | | not null |
그래프가 이미 내준 id를 다시 쓰면 (graphid, labid)에 걸린 고유 인덱스에서 실패합니다.
마지막으로 예제가 만든 그래프를 지웁니다:
DROP GRAPH filmstore CASCADE;
참고#
레이블 이름은 수식할 수 없습니다. CREATE VLABEL filmstore.film은 구문 오류이고, 그래프는 항상
graph_path에서 옵니다. 설정된 것이 없으면 이 문장은 graph_path is NULL로 멈춥니다.
\dGv는 정점 레이블을 나열하고 일치하는 것마다 설명해 줍니다. \dGl은 두 종류의 레이블을 자세한
설명 없이 나열합니다.
참고
enable_property_promotion은 Cypher의 속성 읽기를 승격된 컬럼에서 답할지 결정합니다. 기본값은
켜짐이고, 그것을 끄면 실행 계획뿐 아니라 결과도 달라질 수 있습니다. 컬럼은 자기 타입의 규칙으로
값을 비교하고 정렬하지만, jsonb 컬럼인 properties는 jsonb 순서를 쓰기 때문입니다.
호환성#
ISO/IEC 39075 (GQL)#
GQL에는 레이블 DDL이 없습니다. 표준의 스키마 장치는 그래프 타입,
<create graph type statement>(§12.6)입니다. 그래프 타입은 그래프 하나 전체에 대해 정점 타입과 간선
타입을 한 번에 선언하고, 그것을 참조하는 그래프를 제약합니다. AgensGraph는 레이블을 하나씩
선언하고, 그 그래프는 열려 있습니다. 레이블은 자기 정점이 어떤 속성을 지녀야 하는지 제한하지
않습니다. 그래프 타입은 GQL 적합성 표에 계획으로 기록돼
있습니다.
PostgreSQL#
CREATE VLABEL은 CREATE TABLE에 대응합니다. UNLOGGED, IF NOT EXISTS, INHERITS, WITH,
TABLESPACE는 거기서와 같은 뜻이고, 승격 속성 형태는 GENERATED ALWAYS AS ... STORED 생성
컬럼입니다. 나머지는 CREATE TABLE에 없습니다. 직접 고를 수 없는 고정된 컬럼 목록, ag_label과
ag_label_property 등록, 자동으로 붙는 부모, 그리고 순서가 중요한 옵션 배치입니다. 반대 방향으로는,
enable_graph_ddl을 켜 두지 않으면 레이블의 테이블을 ALTER TABLE로 다시 모양 잡을 수 없습니다.
ALTER VLABEL·ALTER ELABEL을 참고하십시오.