콘텐츠로 이동

Create Graph

AkasicDB에서 그래프 질의를 수행하기 위한 준비 단계인 그래프 생성 과정을 안내합니다. SQL 질의를 이용해 그래프 스키마를 정의하고, 관계형 데이터로부터 그래프를 생성하는 방법을 설명합니다.


테이블 준비

아래 질의는 관계형 스키마만을 포함합니다. 각 테이블에 데이터를 채우는 질의는 아래의 "테이블 데이터 채우기" 부분을 펼쳐서 확인할 수 있습니다.

CREATE TABLE store (
    s_id        integer PRIMARY KEY,
    name        varchar(50),
    manager     varchar(40)
);

CREATE TABLE item (
    i_no        integer PRIMARY KEY,
    name        varchar(50),
    price       decimal(7,2)
);

CREATE TABLE customer (
    c_id        integer PRIMARY KEY,
    first_name  varchar(20),
    last_name  varchar(30)
);

CREATE TABLE orders (
    c_id        integer,
    i_no        integer,
    s_id        integer
);

ALTER TABLE orders ADD CONSTRAINT fk_orders_customer
FOREIGN KEY (c_id) REFERENCES customer(c_id);

ALTER TABLE orders ADD CONSTRAINT fk_orders_item
FOREIGN KEY (i_no) REFERENCES item(i_no);

ALTER TABLE orders ADD CONSTRAINT fk_orders_store
FOREIGN KEY (s_id) REFERENCES store(s_id);
테이블 데이터 채우기
INSERT INTO store (s_id, name, manager)
VALUES
    (1, 'ought', 'William Ward'),
    (2, 'able', 'Scott Smith'),
    (3, 'able', 'Scott Smith'),
    (4, 'ese', 'Edwin Adams'),
    (5, 'anti', 'Edwin Adams');


INSERT INTO item (i_no, name, price)
VALUES
    (1, 'ought', 27.02),
    (2, 'able', 1.12),
    (3, 'pri', 7.11),
    (4, 'ese', 1.35),
    (5, 'anti', 4.00),
    (6, 'cally', 0.85),
    (7, 'ation', 9.94),
    (8, 'eing', 2.76),
    (9, 'n st', 4.46),
    (10, 'barought', 8.94),
    (11, 'oughtought', 54.87),
    (12, 'ableought', 6.54),
    (13, 'priought', 8.76),
    (14, 'eseought', 1.85),
    (15, 'antiought', 2.57),
    (16, 'callyought', 0.31),
    (17, 'ationought', 6.49),
    (18, 'eingought', 0.87),
    (19, 'n stought', 10.61),
    (20, 'barable', 29.35);

INSERT INTO customer (c_id, first_name, last_name)
VALUES
    (1, 'Javier', 'Lewis'),                         
    (2, 'Amy', 'Moses'),                         
    (3, 'Latisha', 'Hamilton'),                      
    (4, 'Michael', 'White'),                         
    (5, 'Robert', 'Moran'),                         
    (6, 'Brunilda', 'Sharp'),                         
    (7, 'Fonda', 'Wiles'),                         
    (8, 'Ollie', 'Shipman'),                       
    (9, 'Karl', 'Gilbert'),                       
    (10, 'Albert', 'Brunson'),                       
    (11, 'Betty', 'Williams'),                      
    (12, 'Margaret', 'Farias'),                        
    (13, 'Rosalinda', 'Grimes'),                        
    (14, 'Jack', 'Wilcox'),                        
    (15, 'Margie', 'Browning'),                      
    (16, 'Lee', 'Stovall'),                       
    (17, 'Brad', 'Lynch'),                         
    (18, 'Andre', 'Moore'),                         
    (19, 'Stanton', 'Dallas'),                        
    (20, 'Naomi', 'Barnett'),                       
    (21, 'Victor', 'Martinez'),                      
    (22, 'Paul', 'Morris'),                        
    (23, 'Nancy', 'Mccormick'),                     
    (24, 'Monique', 'Baker'),                         
    (25, 'Shawn', 'Prather'),                       
    (26, 'Edith', 'Hernandez'),                     
    (27, 'Margaret', 'Collins'),                       
    (28, 'Pamela', 'Luna'),                          
    (29, 'William', 'Craig'),                         
    (30, 'Kenneth', 'Wood');                          

INSERT INTO orders (c_id, i_no, s_id)
VALUES
    (9,7,4),
    (11,14,1),
    (16,12,3),
    (17,17,3),
    (6,14,4),
    (18,14,4),
    (27,14,4),
    (12,17,4),
    (28,8,1),
    (22,5,2),
    (23,14,4),
    (24,14,1),
    (24,3,5),
    (4,8,3),
    (10,8,4),
    (4,18,3),
    (28,15,5),
    (12,2,2),
    (15,18,1),
    (12,20,1),
    (16,10,3),
    (17,1,4),
    (24,19,3),
    (6,10,5),
    (30,6,1),
    (19,12,4),
    (21,5,4),
    (7,17,3),
    (26,9,2),
    (25,16,3),
    (13,9,5),
    (17,15,1),
    (29,7,2),
    (25,4,2),
    (5,6,3),
    (18,9,2),
    (10,1,4),
    (22,16,4),
    (12,10,5),
    (20,15,3),
    (19,7,2),
    (10,11,1),
    (3,6,2),
    (17,12,5),
    (18,5,5),
    (19,18,5),
    (23,8,1),
    (6,13,1),
    (9,18,1),
    (3,5,1),
    (17,6,4),
    (9,11,4),
    (14,3,4),
    (23,12,1),
    (25,6,3),
    (7,10,4),
    (14,4,5),
    (11,4,1),
    (9,10,5),
    (17,16,3),
    (11,7,4),
    (26,4,2),
    (7,18,2),
    (19,2,5),
    (22,18,2),
    (26,7,3),
    (27,3,5),
    (8,17,4),
    (26,2,4),
    (6,6,5),
    (27,6,3),
    (22,20,3),
    (27,6,2),
    (30,2,5),
    (13,18,3),
    (6,18,2),
    (28,7,1),
    (27,12,5),
    (5,8,1),
    (27,11,3),
    (9,10,5),
    (27,2,2),
    (8,18,5),
    (22,5,2),
    (27,16,5),
    (29,9,5),
    (30,2,4),
    (30,8,5),
    (29,3,4),
    (30,20,4),
    (22,5,2),
    (4,1,1),
    (29,8,3),
    (19,6,2),
    (15,17,5),
    (15,15,3),
    (6,20,1),
    (14,15,4),
    (18,13,3),
    (18,15,4);

그래프 스키마 정의

그래프 정의 추가

  • 새로운 그래프 정의 추가
-- 그래프 'retail_graph'를 정의
SELECT akasicdb.define_graph('retail_graph');

함수 인자 설명

akasicdb.define_graph(
    graph_name  -- 정의할 그래프의 이름
);
  • 기존 그래프 정의 복사 (정점, 간선 정의 포함)
-- 그래프 정의 'retail_graph'를 복사한 새로운 그래프 'retail_graph2'를 정의
SELECT akasicdb.copy_graph(
  'retail_graph', 
  'retail_graph2'
);

함수 인자 설명

akasicdb.copy_graph(
    src_graph_name,   -- 복사할 그래프 정의 이름
    dst_graph_name    -- 새로 정의할 그래프의 이름
);

Warning

akasicdb.copy_graph는 그래프 스키마(정점/간선 정의)만 복사합니다.

akasicdb.create_graph()로 이미 생성한 그래프라 하더라도 데이터가 복사되거나 새 그래프가 자동으로 생성되지 않습니다.

정점 정의 추가

-- 그래프 정의 retail_graph에 정점 정의 v_city를 추가
-- 각 정점은 속성으로 name과 population을 가지며 각각 text 타입, int 타입으로 저장됨
SELECT akasicdb.define_vertex(
  'retail_graph',
  'v_city',
  ARRAY['name text', 'population integer']
);

-- 그래프 정의 retail_graph에 정점 정의 v_item을 추가
-- item 테이블의 각 튜플로부터 정점이 추출됨
SELECT akasicdb.define_vertex(
  'retail_graph', 
  'v_item', 
  ARRAY['i_no integer', 'name varchar(50)', 'price decimal(7,2)'],
  'item'
);

-- 그래프 정의 retail_graph에 정점 정의 v_store를 추가
-- store 테이블에 대한 질의 결과의 각 튜플로부터 v_store 정점이 추출됨
SELECT akasicdb.define_vertex(
  'retail_graph', 
  'v_store', 
  ARRAY['s_id integer', 'name varchar(50)'], 
  'store',
  'SELECT s_id, name FROM store'
);

함수 인자 설명

akasicdb.define_vertex(
    graph_name,    -- 정점 정의를 추가할 그래프 정의의 이름
    vertex_label,  -- 추가할 정점의 레이블
    property_list, -- 정점의 속성 리스트 (null의 경우 속성이 없는 정점으로 저장됨)
    vertex_table,  -- (옵션) 정점으로 변환될 튜플들이 저장된 테이블
    query          -- (옵션) 정점으로 변환될 튜플들을 필터링하고, 정점에 속성을 부여하기 위한 질의
);
정점 정의 추가는 일반적인 관계형 DB에서 테이블을 정의하는 것과 비슷합니다. 정점 레이블(vertex_label)과 속성 리스트(property_list)가 각각 관계형 DB에서의 테이블 이름과 column 리스트에 해당합니다.

vertex_tablequery 파라미터는 기존 테이블 데이터로부터 정점을 생성할 때 사용합니다.

vertex_table만 사용할 경우에는 해당 테이블의 모든 컬럼이 정점의 속성으로 저장됩니다. 이때, property_list에 명시된 속성명이 기존 테이블의 컬럼명과 일치해야 합니다.

query를 지정할 경우, 해당 질의에 대한 결과 튜플로부터 정점이 추출됩니다. 이때, 각 튜플의 컬럼이 속성으로 저장되기 때문에 property_list에 명시된 속성명이 질의의 SELECT 절과 일치해야 합니다. 또한 query 파라미터는 아래의 규칙을 따라야 합니다.

  • SELECT-FROM-WHERE 형태의 질의로 단일 테이블(vertex_table)에 대한 질의여야 합니다.
  • ORDER BY, GROUP BY, WITH를 포함한 다른 절들은 지원되지 않습니다.
  • WHERE 절에는 단순 이항 표현식(예: A.x = B.y AND A.x = 100)의 AND 연산만 허용됩니다.
  • SELECT 절에는 단순 열 참조(예: A.x), 산술 연산(예: A.x+B.y*C.z), 함수 호출(예: abs(), substr())이 지원됩니다.

Note

정점을 생성하면 사용자가 지정한 속성 외에도 vertex_id라는 속성이 저장됩니다. 이 값은 각 정점의 식별자(identifier)로, 그래프 연산 시 사용하기 위해 생성된 내부 ID입니다. vertex_tablequery 파라미터를 사용할 때 원본 테이블의 PK 값을 그래프 내에서 직접 사용해야 할 경우, 정점 정의 시에 PK를 속성으로 지정하시기 바랍니다.

간선 정의 추가

-- v_store, v_city 정점을 연결하는 located_in 간선을 정의
-- 각 간선은 속성으로 since를 가지며, timestamptz 타입으로 저장됨
SELECT akasicdb.define_edge(
  'retail_graph', 
  'located_in',
  'v_store', 'v_city',
  ARRAY['since timestamptz']
);

-- v_store, v_item 정점을 연결하는 sell 간선을 정의 
-- 질의 결과의 각 튜플이 sell 간선으로 추출됨
-- 간선의 속성은 없으며, v_store/v_item 정점은 질의의 store 테이블과 item 테이블의 튜플과 매칭됨
SELECT akasicdb.define_edge(
  'retail_graph', 
  'sell',
  'v_store', 'v_item',
  null,
  'SELECT null FROM store s, orders o, item i 
   WHERE s.s_id = o.s_id AND i.i_no = o.i_no',
  'store s', 'item i'
);

함수 인자 설명

akasicdb.define_edge(
    graph_name,       -- 간선 정의를 추가할 그래프 정의 이름
    edge_label,       -- 추가할 간선의 레이블
    src_vertex_label, -- 출발 정점의 레이블 
    dst_vertex_label, -- 도착 정점의 레이블 
    property_list,    -- 간선의 속성 리스트 (null의 경우 속성이 없는 간선으로 저장됨)
    query,            -- (옵션) 출발 정점과 도착 정점 간의 관계를 정의한 질의
    src_table,        -- (옵션) query 파라미터 내에서 출발 정점에 해당하는 테이블
    dst_table         -- (옵션) query 파라미터 내에서 도착 정점에 해당하는 테이블
);
간선 정의도 정점 정의와 마찬가지로 간선 레이블(edge_label)과 속성 리스트(property_list)가 각각 관계형 DB에서의 테이블명과 column 리스트에 해당합니다.

다만 간선을 정의할 때는 연결하는 출발/도착 정점 레이블까지 같이 명시해야 합니다. 이는 관계형 DB에서 FK를 정의할 때 참조할 테이블을 지정하는 것과 같습니다.

query, src_table, dst_table 파라미터는 기존 테이블 데이터로부터 간선을 생성할 때 사용합니다.

query 파라미터를 사용하면 해당 질의의 결과 튜플로부터 간선이 추출됩니다. 이때, 각 튜플의 컬럼이 속성으로 저장되기 때문에 property_list에 명시된 속성명이 질의의 SELECT 절과 일치해야 합니다.

src_tabledst_table은 간선을 정의하는 질의에서 출발/도착 정점을 명시하기 위한 파라미터로, query 파라미터를 사용할 경우 필수적으로 명시해야 합니다. 시작점/끝점에 해당하는 정점 정의에 사용한 vertex_table과 같아야 하며, 질의 내에서 약칭(abbreviation)을 사용했을 경우 약칭까지 함께 명시해야 합니다(위의 예시에서 store s, item i와 같은 식).

query 파라미터는 아래의 규칙을 따라야 합니다.

  • SELECT-FROM-WHERE 형태의 질의로 src_tabledst_table 간의 join 관계를 포함해야만 합니다.
  • Aggregation(GROUP BYHAVING)을 지원합니다.
  • ORDER BY, WITH, LIMIT을 포함한 다른 절들은 지원하지 않습니다.
  • WHEREHAVING 절에는 단순 이항 표현식(예: A.x = B.y AND A.x = 100)의 AND 연산만 허용됩니다.
  • SELECTGROUP BY 절에는 단순 열 참조(예: A.x), 산술연산(예: A.x+B.y*C.z), 집계연산(예: COUNT(), AVG()), 함수 호출(예: abs(), substr())이 지원됩니다.

Note

간선을 생성하면 사용자가 지정한 속성 외에도 src_vertex_id, dst_vertex_id, edge_id라는 속성이 저장됩니다. 이 중 <src/dst>_vertex_id의 경우 간선이 연결하는 시작/끝 정점의 식별자이며, edge_id는 각 간선의 식별자입니다.

이 속성들은 정점의 vertex_id와 마찬가지로 그래프 연산 시 사용하기 위해 생성된 내부 ID입니다. 원본 테이블의 PK 값을 그래프 내에서 직접 사용해야 할 경우, 간선 정의 시에 PK를 속성으로 지정하시기 바랍니다.

그래프 정의 삭제

-- 그래프 정의 'retail_graph'를 삭제
SELECT akasicdb.undefine_graph('retail_graph');

함수 인자 설명

akasicdb.undefine_graph(
    graph_name -- 삭제할 그래프 정의의 이름
);
그래프 정의를 삭제할 경우, 해당 그래프 정의에 포함된 정점/간선 정의 또한 삭제됩니다.

정점 정의 삭제

-- 그래프 정의 'retail_graph'로부터 정점 정의 'v_item' 삭제
SELECT akasicdb.undefine_vertex('retail_graph', 'v_item');

함수 인자 설명

akasicdb.undefine_vertex(
    graph_name,   -- 정점 정의를 제거할 그래프 정의 
    vertex_label  -- 제거할 정점 정의의 레이블
);
정점 정의를 삭제할 경우, 해당 정점 정의와 연결된 간선 정의 또한 삭제됩니다.

간선 정의 삭제

-- 그래프 정의 'retail_graph'로부터 간선 정의 'sell' 삭제
SELECT akasicdb.undefine_edge('retail_graph', 'sell');

함수 인자 설명

akasicdb.undefine_edge(
    graph_name,   -- 간선 정의를 제거할 그래프 정의 
    edge_label    -- 제거할 간선 정의의 레이블
);

그래프 생성 및 삭제

그래프 생성

-- 그래프 정의 `retail_graph`를 기반으로 그래프 생성
SELECT akasicdb.create_graph('retail_graph');

-- 이미 retail_graph가 생성되어 있을 경우, 이를 제거하고 재생성
SELECT akasicdb.create_graph('retail_graph', replace_if_exists:=true);

함수 인자 설명

akasicdb.create_graph(
  graph_name,       -- 생성할 그래프의 이름 (= 그래프 생성에 필요한 그래프 정의의 이름)
  replace_if_exists -- (옵션) true 혹은 false, 기본값은 false
                    -- true일 경우, 이미 존재하는 그래프를 제거하고 다시 그래프를 생성
                    -- false일 경우, 이미 그래프가 존재한다면 에러를 반환          
);

그래프가 생성된 후에도 그래프 스키마 정의 질의를 사용하여 그래프 정의를 수정할 수 있습니다. 그러나 그래프의 정의만 수정될 뿐 이미 생성된 그래프는 수정되지 않습니다.

수정된 그래프 정의를 그래프 데이터에 반영하기 위해서는, replace_if_exists 옵션을 사용해서 그래프를 재생성해야 합니다.

Warning

AkasicDB 커뮤니티 에디션의 경우, 그래프의 정점/간선 수에 제한이 있습니다. 각 정점/간선 레이블마다 최대 1,000,000 (1M)개의 정점/간선만 생성할 수 있습니다.

그래프 삭제

-- 생성된 그래프 'retail_graph'만 삭제
SELECT akasicdb.delete_graph('retail_graph');

-- 생성된 그래프와, 그래프 정의까지 모두 삭제
SELECT akasicdb.delete_graph('retail_graph', remove_definition:=true);

함수 인자 설명

akasicdb.delete_graph(
    graph_name,         -- 삭제할 그래프의 이름
    remove_definition   -- (옵션) true 혹은 false, 기본값은 false
                        -- true일 경우, 그래프 정의까지 제거
                        -- false일 경우, 생성된 그래프만 제거하고, 그래프 정의는 유지
);