Graph Query
AkasicDB에서 akaiscdb.cypher() 함수를 통해 그래프 질의를 수행하는 방법을 안내합니다.
1. 그래프 준비
테이블 준비는 링크를 참고해주세요.
-- 그래프 'retail_graph'를 정의
SELECT akasicdb.define_graph('retail_graph');
-- 그래프 정의 'retail_graph'에 정점 정의 'v_item', 'v_customer', 'v_store' 추가
SELECT akasicdb.define_vertex('retail_graph', 'v_item', 'item');
SELECT akasicdb.define_vertex('retail_graph', 'v_customer', 'customer');
SELECT akasicdb.define_vertex('retail_graph', 'v_store', 'store');
-- 그래프 정의 'retail_graph'에 간선 정의 'buy', 'sell' 추가
SELECT akasicdb.define_edge('retail_graph', 'sell',
'v_store', 'store s',
'v_item', 'item i',
'SELECT null FROM store s, orders o, item i '
'WHERE s.s_id = o.s_id AND i.i_no = o.i_no');
SELECT akasicdb.define_edge('retail_graph', 'buy',
'v_customer', 'customer c',
'v_item', 'item i',
'SELECT null FROM customer c, orders o, item i '
'WHERE c.c_id = o.c_id AND i.i_no = o.i_no');
-- 그래프 정의 'retail_graph'에 간선 정의 'co_purchase' 추가
SELECT akasicdb.define_edge('test', 'co_purchase',
'v_customer', 'customer c1',
'v_customer', 'customer c2',
'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');
-- 그래프 정의 `retail_graph`를 기반으로 그래프 생성
SELECT akasicdb.create_graph('retail_graph');
2. Cypher 질의 인터페이스
함수 인자 설명
akasicdb.cypher(
graph_name NAME, -- 질의를 수행할 그래프 이름
query_string TEXT -- 수행할 cypher 질의
);
그래프 질의는 cypher 질의의 형태를 띄어야 합니다. 이때,
query_string의 경우 $$(dollar quote)로 둘러싸인 문자열이어야 합니다. 또한,akasicdb.cypher()호출 뒤에는AS절을 붙여서, cypher 질의의 결과를 SQL 질의에서 튜플의 형태로 다룰 수 있도록 해야 합니다.
2.1 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('test', $$
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
);
2.2 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
);
2.3. 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.vertex_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
)
2.4. VLE(Variable Length Edge) 패턴
-- co_purchase 간선을 통해 비슷한 구매 이력을 가진 소비자의 네트워크를 구축했을 때,
-- Latisha Hamilton으로부터 거리 1~3 이내의 소비자를 조회
SELECT *
FROM akasicdb.cypher('test', $$
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 수가 크더라도 좋은 성능이 유지될 수 있습니다.
2.5. Cypher 내에서 파라미터 사용하기
-- 파라미터(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
);
- Cypher 질의 내에서 파라미터는 $로 시작하는 심볼(위의
$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타입으로 처리됩니다. - 정수형 등의 다른 타입을 써야 할 경우 질의 내에서 명시적으로 타입 캐스팅을 해야 합니다.