Graph Query¶
AkasicDB에서 그래프 질의를 수행하는 방법을 안내합니다.
그래프 준비¶
테이블 준비는 링크를 참고해주세요.
-- 그래프 'retail_graph'를 정의
SELECT akasicdb.define_graph('retail_graph');
-- 그래프 정의 'retail_graph'에 정점 정의 'v_item', 'v_customer', 'v_store' 추가
SELECT akasicdb.define_vertex(
'retail_graph',
'v_item',
ARRAY['i_no integer', 'name varchar(50)', 'price decimal(7,2)'],
'item'
);
SELECT akasicdb.define_vertex(
'retail_graph',
'v_customer',
ARRAY['c_id integer', 'first_name varchar(20)', 'last_name varchar(30)'],
'customer'
);
SELECT akasicdb.define_vertex(
'retail_graph',
'v_store',
ARRAY['s_id integer', 'name varchar(50)'],
'store',
'SELECT s_id, name FROM store'
);
-- 그래프 정의 'retail_graph'에 간선 정의 'buy', 'sell' 추가
SELECT akasicdb.define_edge(
'retail_graph',
'buy',
'v_customer', 'v_item',
null,
'SELECT null FROM customer c, orders o, item i '
'WHERE c.c_id = o.c_id AND i.i_no = o.i_no',
'customer c', 'item i'
);
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'
);
-- 그래프 정의 'retail_graph'에 간선 정의 'co_purchase' 추가
SELECT akasicdb.define_edge(
'retail_graph',
'co_purchase',
'v_customer', 'v_customer',
null,
'SELECT null '
'FROM customer c1, orders o1, item i, orders o2, customer c2 '
'WHERE c1.c_id = o1.c_id AND i.i_no = o1.i_no '
'AND c2.c_id = o2.c_id AND i.i_no = o2.i_no',
'customer c1', 'customer c2'
);
-- 그래프 정의 'retail_graph'를 기반으로 그래프 생성
SELECT akasicdb.create_graph('retail_graph');
SQL/GQL 질의 인터페이스¶
SQL/GQL이란?¶
SQL/GQL은 AkasicDB의 그래프·벡터·관계형 질의 문법입니다. akasicdb.cypher() 함수를 통해 ISO 공식 그래프 질의 언어인 GQL을 사용할 수 있습니다. 또한 그래프 질의의 결과를 PostgreSQL 테이블처럼 후처리하거나, 다른 관계형 질의와 결합할 수 있습니다. Vector Features - Querying에서 설명할 벡터 연산자도 직접 GQL 질의 내에서 사용할 수 있습니다.
함수 인자 설명
akasicdb.cypher()의 기본 사용법:
akasicdb.cypher()에 파라미터를 포함한 형태:
akasicdb.cypher(
graph_name NAME, -- 질의를 수행할 그래프 이름
query_string TEXT, -- 수행할 그래프 질의
parameters JSONB -- JSON 형식의 파라미터 값
);
그래프 질의는 아래의 SQL/GQL 제약을 따르는 GQL(openCypher) 계열 문법으로 작성해야 합니다. 이때, query_string의 경우 $$(dollar quote)로 둘러싸인 문자열이어야 합니다. 또한, akasicdb.cypher() 호출 뒤에는 AS 절을 붙여서, 그래프 질의의 결과를 SQL 질의에서 튜플의 형태로 다룰 수 있도록 해야 합니다.
Basic Traversal¶
-- 이름이 Margaret인 소비자의 풀네임을 조회
SELECT *
FROM akasicdb.cypher('retail_graph', $$
MATCH (c:v_customer)
WHERE c.first_name = 'Margaret'
RETURN
c.first_name as first_name,
c.last_name as last_name
$$) as (
first_name varchar,
last_name varchar
);
-- Margaret Farias와 같은 상품을 구매한 다른 소비자의 이름을 조회
SELECT *
FROM akasicdb.cypher('retail_graph', $$
MATCH (c1:v_customer)-[:buy]->(i:v_item)<-[:buy]-(c2:v_customer)
WHERE c1.first_name = 'Margaret'
AND c1.last_name = 'Farias'
AND c1.vertex_id <> c2.vertex_id
RETURN
c2.first_name as first_name,
c2.last_name as last_name
$$) as (
first_name varchar,
last_name varchar
);
WITH Clause¶
-- Margaret Farias가 상품을 구매한 상점에서 판매하는 다른 상품들을 조회
SELECT item_name
FROM akasicdb.cypher('retail_graph', $$
MATCH (c:v_customer)-[:buy]->(i1:v_item)<-[:sell]-(s1:v_store)
WHERE c.first_name = 'Margaret'
AND c.last_name = 'Farias'
WITH DISTINCT s1.vertex_id AS store_id
MATCH (s2:v_store)-[:sell]->(i2:v_item)
WHERE s2.vertex_id = store_id
RETURN
DISTINCT i2.name AS item_name
$$) as (
item_name char
);
Aggregation¶
-- Margaret Farias가 특정 상점에서 구매한 상품의 이름과 구매한 수량을 조회
SELECT item_name, cnt
FROM akasicdb.cypher('retail_graph', $$
MATCH (c:v_customer)-[:buy]->(i:v_item)<-[:sell]-(s:v_store)
WHERE s.s_id = 1
AND c.first_name = 'Margaret'
AND c.last_name = 'Farias'
RETURN
i.name AS item_name,
count(i.name) AS cnt
$$) as (
item_name char,
cnt integer
)
VLE(Variable Length Edge) 패턴¶
-- co_purchase 간선을 통해 비슷한 구매 이력을 가진 소비자의 네트워크를 구축했을 때,
-- Latisha Hamilton으로부터 거리 1~3 이내의 소비자를 조회
SELECT *
FROM akasicdb.cypher('retail_graph', $$
MATCH (c1:v_customer)-[:co_purchase*1..3 SHORTEST]->(c2:v_customer)
WHERE c1.first_name = 'Latisha' AND c1.last_name = 'Hamilton'
RETURN
c2.first_name as first_name,
c2.last_name as last_name
$$) as (
first_name varchar,
last_name varchar
);
- VLE(Variable Length Edge)와 TC(Transitive Closure) 패턴의 경우, 아래의 제약이 있습니다.
- 시작/끝 정점 레이블이 동일한 단일 간선 레이블만 사용할 수 있습니다.
- 탐색을 시작하는 정점(위 경우
c1)이 필터링되지 않을 경우 매우 느릴 수 있습니다. - 탐색할 hop 수가 클 경우 매우 느릴 수 있습니다. 단,
SHORTEST가 포함될 경우 hop 수가 크더라도 좋은 성능이 유지될 수 있습니다.
그래프 질의 내에서 파라미터 사용하기¶
-- 파라미터(customer_name, 값: Margaret)와 같은 이름을 가진 소비자의 풀네임을 조회
SELECT *
FROM akasicdb.cypher('retail_graph', $$
MATCH (c:v_customer)
WHERE c.first_name = $customer_name
RETURN
c.first_name as first_name,
c.last_name as last_name
$$, '{"customer_name":"Margaret"}') as (
first_name varchar,
last_name varchar
);
- 그래프 질의 내에서 파라미터는 $로 시작하는 심볼(위의
$customer_name)로 나타납니다. - 파라미터 값은 JSON 형식으로 함수에 전달할 수 있습니다.
-- 파라미터(customer_id, 값: 1)와 같은 `c_id`를 가지는 소비자의 풀네임을 조회
SELECT *
FROM akasicdb.cypher('retail_graph', $$
MATCH (c:v_customer)
WHERE c.c_id = $customer_id::integer
RETURN
c.first_name as first_name,
c.last_name as last_name
$$, '{"customer_id":1}') as (
first_name varchar,
last_name varchar
);
- 파라미터 값은 질의 내에서 기본적으로
TEXT타입으로 처리됩니다. - 정수형 등의 다른 타입을 써야 할 경우 질의 내에서 명시적으로 타입 캐스팅을 해야 합니다.
- SQL/GQL에서는 openCypher의
toInteger()와 같은 변환 함수 대신::integer와 같은 SQL 스타일 타입 캐스팅을 사용합니다. 단, 특수문자 등을 포함한 경우::'int[]'와 같이 타입 이름을 작은따옴표로 감싸서 사용해야 합니다.
SQL/GQL 사용 시 유의사항¶
SQL/GQL의 그래프 질의는 openCypher와 비슷하지만 지원되는 문법 범위와 사용 방식에서 몇 가지 차이점이 있습니다. 미지원 문법의 경우 추후 업데이트에서 추가될 수 있습니다.
아래 예시를 사용하기 전에 다음 패턴 규칙을 확인해 주세요.
- 그래프 패턴에 정점 또는 간선이 처음 등장할 때는 반드시 하나의 레이블을 명시해야 합니다. 레이블이 없거나 여러 레이블을 지정한 패턴 대신
(c:v_customer)-[r:buy]->(i:v_item)와 같은 형태를 사용해 주세요. -
모든 간선은 방향성이 있습니다. 탐색 시 정방향(
->) 또는 역방향(<-) 중 하나를 선택해야 하며,--와 같은 무방향 간선 패턴은 지원하지 않습니다. -
OPTIONAL MATCH는 현재 지원하지 않습니다. 다만 SQL의 outer join을 사용해서 SQL/GQL에서 유사한 동작의 질의를 작성할 수 있습니다. -
UNION등의 집합 연산은 현재akasicdb.cypher()내에서 지원하지 않습니다. 필요한 경우 SQL의 집합 연산을 통해 SQL/GQL에서 유사한 동작의 질의를 작성할 수 있습니다.openCypher SQL/GQL -
(v:vertex_label {key: "Value"})와 같은 property map은 지원하지 않습니다.WHERE절에 속성 관련 조건을 넣는 것으로 같은 동작의 질의를 작성할 수 있습니다.openCypher SQL/GQL -
exists()및 path variable은 현재 지원하지 않습니다. -
WITH/RETURN절에서 정점/간선 자체를 반환하는 문법은 지원하지 않습니다. -
IN연산자는 현재akasicdb.cypher()내에서 지원하지 않습니다. -
openCypher의
collect()함수 대신 PostgreSQL의array_agg()함수를 사용하셔야 합니다.openCypher SQL/GQL -
배열 타입의 인덱스가 1부터 시작합니다.
-
List comprehension은 현재 지원하지 않습니다.
-
CALLsubquery는 현재 지원하지 않습니다. -
labels(n),type(r),properties(n)과 같은 openCypher 헬퍼 함수는 현재 지원하지 않습니다. 레이블은 패턴에 직접 지정하고, 속성은 이름으로 직접 접근해 주세요. -
openCypher의
id()함수는 현재 지원하지 않습니다. 정점은n.vertex_id, 간선은r.edge_id와 같은 내부 ID 속성을 직접 사용해 주세요. -
ORDER BY에서는 같은RETURN절에서 만든 alias를 참조할 수 없습니다. 그래프 질의 안에서는 원래 표현식 또는 속성으로 정렬하거나, 바깥 SQL 질의에서 반환 alias를 기준으로 정렬해 주세요.