성장通

06. 관계형을 그래프로 본문

그래프/그래프 데이터

06. 관계형을 그래프로

백악기작은펭귄 2024. 2. 18. 23:17

관계형을 그래프로

전 세계의 기술 팀은 데이터 관리 문제를 해결하는 방법 중 하나로 그래프 데이터를 채택하고 있다. 그래프 데이터 형식이 기존의 관계형 솔루션 대비 가지는 이점은 데이터 내 관계 모델링, 저장 그리고 검색을 하는데에 있어 유용성을 들 수 있다. 이러한 이점이 부각되는 문제에서 관계형 솔루션을 사용하고 있었다면 그래프 데이터 솔루션으로의 이동을 고려해 볼 만하다. 하지만 이를 위해서는 데이터의 변환 및 통합이 필요한데, 관계형으로 구축된 데이터를 처리하는 과정에서 종종 어려움을 겪곤 한다. 이러한 어려움을 최소화하기 위해, 우리는 그래프 데이터 어플리케이션을 시작하기 위한 공통 과정을 정의하고 표준화할 것이다. 또한 Customer360(이하 C360) 예제를 이용해 관계형과 그래프 기술을 각각 이용해서 아키텍처 구축을 연습해 볼 것이다. 그리고 이러한 내용을 정리하여 시스템 요구 사항에 맞는 올바른 선택을 위한 가이드를 작성해 볼 것이다.

 

데이터의 통합과 접근

소비자 데이터를 하나의 어플리케이션에 통합함으로써 다양한 요구에 대응할 수 있도록 하자는 발상은 이미 데이터 웨어하우스(data warehouse)나 데이터 레이크(data lake) 개념에서 등장하였다. 하지만 이제는 이러한 통합을 넘어서 접근성까지 고려하는 시대가 되었다. 기존 데이터 레이크 방식에서는 특정 행위를 하기 위한 데이터를 탐색하는 데에 시간이 오래 걸렸다. 따라서 모든 형태의 데이터를 수집할 수 있음에도 불구하고 빠른 데이터 추출을 원하는 최신 디지털 어플리케이션의 메인 데이터 저장방식이 되지 못했다. 하지만 그래프 기술을 활용한 아키텍트는 연결된 검색 시스템을 이용해 빠르게 데이터 탐색을 하고 추출을 진행할 수 있다. 그래프 씽킹 시대가 도래하면서 데이터의 가용성을 높이고 개별 사용자 경험을 제공하는 방법을 찾을 수 있게 된 것이다.

 

예제 데이터: Customer 360

C360은 고객을 비즈니스의 중심 개체로 하여 주요 개체들 간의 관계를 중심으로 어플리케이션을 엔지니어링 하는 프로젝트이다. 고객과 다양한 금융 서비스와의 관계를 이용해 다음 질문에 답할 수 있도록 설계된다.

  1. 고객은 어떤 신용카드를 사용하고 있는가?
  2. 고객은 어느 계좌를 소유하는가?
  3. 고객은 어떤 대출을 받았는가?
  4. 고객의 어떤 정보를 알고 있는가?

소비자는 회사의 서비스를 옴니채널(omnichannel)로 활용한다. 즉 소비자는 다양한 채널을 통해 끊임없이 디지털 공간과 물리적 상점을 오간다. 이렇게 다양한 채널을 통해 고객 데이터가 수집이 될 때, 이를 통합하여 관리하는 어플리케이션의 존재는 기업에게 큰 도움이 될 수 있다. 한 예로, 중국의 바이두(Baidu)는 통합된 데이터 플랫폼을 통해 KFC와 협업해 주문 추천 기능을 만들었다. 이 협업 솔루션은 고객을 식별하고 기존 데이터를 기반으로 메뉴를 추천하는 방법으로, 두 회사의 데이터 통합을 통해 C360을 구축했고, 고유한 이득을 창출했다.

 

C360 관계형으로 구현하기

그래프 시스템과의 비교를 위해, 앞서 설명한 C360(Customer360) 데이터를 저장하고 관리하는 시스템을 관계형 시스템으로 구축해보도록 하겠다. 우리의 목표는 C360 같은 데이터를 다룰 때 그래프에 비해 관계형이 얼마나 더 복잡한지를 확인하기 위함이니 관계형 시스템 아키텍처에 대한 자세한 설명을 생략하도록 하겠다.

 

이번 구현에서는 SQL 질의 언어와 Postgres RDBMS를 사용할 것이며, 예제 데이터는 다음과 같다.

 

 

데이터 모델

위 데이터에 대한 개념적 모델은 다음과 같이 구성할 수 있다.

 

 

위 개념적 모델에 동의했다면 이제 데이터베이스 설계를 시작해 보도록 하자. 데이터베이스 설계 시 주로 채택하는 방법은 ERD(Entity-Relation-Diagram) 방식으로, 데이터 모델을 개체 간의 관계를 이용해 논리적으로 표현하는 방법 중 하나이다.

 

다음 그림에서 개체는 사각형으로 나타나며 관계형 데이터베이스에서는 이를 테이블로 나타낸다. 각 개체 내에는 해당 개체의 속성을 나타내는 프로퍼티들이 나열되어 있으며, 각 개체는 고유 식별자인 Primary Key(이하 PK)를 갖는다. 다음 그림에서 Customer 개체의 식별자는 customer_id, Account 개체의 식별자는 acct_id가 된다.

 

 

위 그림에서 개체 사이의 마름모 모양은 개체 간의 관계를 나타내는 것으로, 개체와 관계 사이 연결 선의 개수로 카디널리티(Cardinality)를 표시한다. 위 예제의 경우 일대다(1-to-many), 다대다(many-to-many) 유형을 확인할 수 있으며, 개체 집합 내 모든 개체가 관계에 참여하고 있는 경우 이중선으로 표시한다. 즉 모든 고객은 Owes와 Owns 관계에 참여한다.

 

고객은 여러 신용 카드를 가질 수 있지만 신용 카드는 오직 한 고객만을 가진다. 또 고객은 여러 대출을 받을 수 있으며 대출 또한 하나의 대출 상품이 여러 고객을 가질 수 있다. 마찬가지로 고객은 여러 계좌(개설 은행)를 가질 수 있고 계좌 또한 여러 고객을 가질 수 있다. 여기서 모든 고객은 계좌를 하나 이상 가지므로 Owns 관계와 Customer 사이 연결선을 이중선으로 나타내었다.

 

관계형에서는 논리적 데이터 모델을 물리적 데이터 모델로 바꾸는 과정이 필요하다. 즉 위 다이어그램을 PK와 FK를 포함하는 테이블로 변환해야 한다. 여기서 PK는 고객 ID나 신용 카드 번호처럼 테이블 내 데이터를 고유하게 식별하는 정보이며, FK(Foreign Key)는 고객 신용 카드 정보아 고객 ID를 함께 저장하는 것과 같이 다른 테이블의 정보에 접근하기 위한 고유하게 식별되는 데이터 정보이다.

 

 

각 테이블은 관계와 개체를 묘사하는 속성을 포함한다. PK 행으로 표현되는 기본 키는 고유한 식별자로 작용하며 테이블 내 특정 행의 정보를 찾기 위해 사용될 수 있다.

 

모든 개체 테이블을 살펴보는 것은 다소 지루하니, PK와 FK를 모두 갖는 Credit Card 개체 테이블을 살펴보도록 하자. 이 테이블은 customer_id를 FK로 사용하여 ERD에서 만든 일대다 관계를 추적한다. 즉, customer_id로 구분되는 고유 사용자에게 관련 신용 카드 정보를 제공하고 있는 것이다. 이처럼 FK를 추가하면 다른 개체 테이블과 연결시킴으로써 일대다 관계를 물리적 데이터 모델에 추가할 수 있다.

 

이번에는 관계 테이블인 Owns와 Owes 테이블을 살펴보자. 이들 테이블은 데이터의 다대다 관계를 물리적으로 저장할 수 있는 조인 테이블(Join table)이다. Owns 테이블은 고객과 계좌 사이 연결을 저장하며 Owes는 고객과 대출 사이 연결을 저장한다. 이러한 조인 테이블을 사이에 둔 두 개체는 각자의 PK를 FK로 제공하며, 따라서 조인 테이블의 PK는 두 FK를 합한 결과로 생각할 수 있다.

 

관계형 구현

위에서 정의한 물리적 데이터 모델에 따라 테이블을 만들고 그 안에 예제 데이터를 삽입해 보도록 하자.

 

1) Customers

CREATE TABLE Customers (
    customer_id TEXT,
    name TEXT,
    PRIMARY KEY (customer_id)
);
INSERT INTO Customers (customer_id, name) VALUES
('c_0', 'Alice'),
('c_1', 'Brian'),
('c_2', 'Chris'),
('c_3', 'Daniel'),
('c_4', 'Erick');

 

2) Accounts, Loans

CREATE TABLE Accounts (
acct_id text,
created_date DATE DEFAULT CURRENT_DATE,
PRIMARY KEY (acct_id)
);

CREATE TABLE Loans (
loan_id text,
created_date DATE DEFAULT CURRENT_DATE,
PRIMARY KEY (loan_id)
);
INSERT INTO Accounts (acct_id) VALUES
('acct_0'),
('acct_5'),
('acct_14');

INSERT INTO Loans (loan_id) VALUES
('loan_18'),
('loan_32'),
('loan_80');

 

3) CreditCards

신용 카드는 고객과 일대다 관계를 맺고 있으므로 customer_id를 FK로 삽입해야 한다.

create table CreditCards(
    cc_num text,
    customer_id text not null,
    created_date date default current_date,
    primary key (cc_num),
    foreign key (customer_id) references Customers(customer_id)
    );
insert into CreditCards (cc_num, customer_id) values
('cc_17', 'c_0'),
('cc_32', 'c_2');

이로써 4가지 개체 테이블을 모두 구현했다. 이제 이 테이블들을 이어주는 조인 테이블을 구현해 보도록 하자.

 

4) Owns, Owes

create table Owns (
    customer_id text not null,
    acct_id text not null,
    created_date date default current_date,
    primary key (customer_id, acct_id),
    foreign key (customer_id) references Customers(customer_id),
    foreign key (acct_id) references Accounts(acct_id)
);

create table Owes (
    customer_id text not null,
    loan_id text not null,
    created_date date default current_date,
    primary key (customer_id, loan_id),
    foreign key (customer_id) references Customers(customer_id),
    foreign key (loan_id) references Loans(loan_id)
);
insert into Owns (customer_id, acct_id) values
('c_0', 'acct_14'),
('c_1', 'acct_14'),
('c_2', 'acct_5'),
('c_3', 'acct_0'),
('c_4', 'acct_0');

insert into Owes (customer_id, loan_id) values
('c_0', 'loan_32'),
('c_3', 'loan_18'),
('c_4', 'loan_18'),
('c_4', 'loan_80');

 

질의 예제

이제 예제 데이터베이스가 준비되었으니 여기에 개체 간의 관계를 파악할 수 있는 4가지 주요 질의를 수행해 보도록 하자.

 

  1. 고객은 어떤 신용카드를 소유하는가? (Customers-CreditCards)
  2. 고객은 어느 계좌를 소유하는가? (Customers-Accounts)
  3. 고객은 어떤 대출을 받았는가? (Customers-Loans)
  4. 고객의 어떤 정보를 알고 있는가? (Customers-ALL)

 

1. 고객은 어떤 신용카드를 소유하는가?

먼저 관계형 데이터베이스를 이용해 고객 c_0가 소유하는 신용 카드를 확인해보자.

SELECT * 
FROM CreditCards
WHERE customer_id = 'c_0';

 

 

위 SQL문의 결과로, 고객 c_0은 신용 카드 cc_17을 소유함을 확인할 수 있었다. 이때 신용 카드 정보와 함께 해당 고객의 정보를 가지고 오고 싶다면 JOIN을 사용해 Customers 테이블과 CreditCards 테이블을 조인해야 한다.

SELECT c.customer_id, c.name,
    cc.cc_num, cc.created_date
FROM Customers AS c
LEFT JOIN CreditCards AS cc ON (c.customer_id = cc.customer_id)
WHERE c.customer_id = 'c_0';

 

고객과 신용 카드 사이는 일대다 관계이므로 조인 구문 하나로 정보를 얻을 수 있었지만, 다대다 관계를 갖는 계좌 혹은 대출과의 관계 정보를 가져오고자 할 때는 좀 더 복잡해진다.

 

2. 고객은 어느 계좌를 소유하는가?

다대다 관계에서는 개체 사이 관계를 나타내는 테이블(여기서는 Owns)을 두 개체 테이블과 함께 조인하여 확인해야 한다.

SELECT c.customer_id, c.name,
    a.acct_id, a.created_date
FROM Customers AS c
LEFT JOIN Owns AS o ON (c.customer_id = o.customer_id)
LEFT JOIN Accounts AS a ON (a.acct_id = o.acct_id)
WHERE c.customer_id = 'c_0';

 

이와 같이 하는 이유는 질의 과정이 다음과 같기 때문이다.

 

1) Customers 테이블에서 c_0 데이터에 접근
2) c_0과 같은 customer_id를 갖는 모든 FK 쌍을 Owns 테이블에서 찾는다
3) FK인 acct_id를 이용해서 Accounts 테이블에 접근 후 정보 추출

이와 비슷한 방법으로 3번 질문에 대한 답변 또한 해보도록 하자.

 

3. 고객은 어떤 대출을 받았는가?

Accounts에서와 동일하게, 그러나 Accounts 대신 Loans를, Owns 대신 Owes를 사용한다는 점이 다르다. 여기서는 다중 데이터가 추출되도록 하기 위해 고객 c_4의 데이터를 살펴보겠다.

SELECT c.customer_id, c.name,
    lo.loan_id, lo.created_date
FROM Customers AS c
LEFT JOIN Owes AS o ON (c.customer_id = o.customer_id)
LEFT JOIN Loans AS lo ON (lo.loan_id = o.loan_id)
WHERE c.customer_id = 'c_4';

 

4. 고객의 어떤 정보를 알고 있는가?

앞서 진행한 세 가지 질의를 종합하면 C360 어플리케이션의 핵심 질의 중 하나인 '고객 정보'에 대한 질의를 수행할 수 있다. 다음과 같은 방식으로 세 가지 질의를 통합하여 하나의 질의로 만들 수 있다.

SELECT Customers.customer_id, Customers.name,
    Accounts.acct_id, Accounts.created_date,
    Loans.loan_id, Loans.created_date,
    CreditCards.cc_num, CreditCards.created_date
FROM Customers
LEFT JOIN Owns ON (Customers.customer_id = Owns.customer_id)
LEFT JOIN Accounts ON (Accounts.acct_id = Owns.acct_id)
LEFT JOIN Owes ON (Customers.customer_id = Owes.customer_id)
LEFT JOIN Loans ON (Loans.loan_id = Owes.loan_id)
LEFT JOIN CreditCards ON (Customers.customer_id = CreditCards.customer_id)
WHERE Customers.customer_id = 'c_0';

이 질의를 통해 C360 생태계 내 고객 c_0의 모든 정보를 추출할 수 있다.

 

결론

몇 종류 안 되는 간단한 개체들만 존재하는 생태계에서, 간단하게 정보를 추출하는 작업만 수행했음에도 질의문이 다소 복잡하다. 물론 좀 더 복잡한 고급 SQL 문법을 다루지 않았으니 이 정도면 할만하다고 생각이 들 수 있는데, 문제가 커지고 복잡해질수록 관계형에서 이를 처리하기란 어려워지는 경향이 있다.

 

이 외에도, 우리는 미리 데이터 관계를 설정하고 데이터를 삽입시킨 후 진행했으니 추출 전에도 데이터 간의 관계를 알고 있었지만, 실제 현장에서 데이터들 간의 관계를 관계형 시스템으로 바로 파악하기란 쉽지 않다.

 

따라서 다음 포스팅에서는 위와 같은 과정을 그래프 시스템으로 구현해 보면서 둘의 차이를 비교해 보도록 하겠다.

'그래프 > 그래프 데이터' 카테고리의 다른 글

05. 그래프의 다중성  (1) 2024.02.03
04. 그래프 스키마 언어  (0) 2024.01.28
03. 관계형에서 그래프 씽킹으로  (1) 2024.01.21
02. 그래프 씽킹  (0) 2023.12.21
01. 떠오르는 그래프 기술  (1) 2023.12.06