DBT를 배웠으니, 이제 로컬에서 한번 가볍게 데이터 파이프라인을 만들어보겠습니다. 물론, 스케줄링이 붙지않아 자동화되지 않겠지만, 추후에 에어플로우와 함께 프로젝트를 진행해보겠습니다.
conda create --name dbt python=3.9
conda activate
python -m pip install dbt-core==1.6
python -m pip install dbt-duckdb==1.6 # duckdb도 설치됨
dbt init
프로젝트의 이름과 프로필 명을 반드시 다르게 해줍니다. 여기서는 woody_dbt_duckdb
, 그리고 dbt_duckdb
가 다른 것을 볼 수 있습니다.
name: 'woody_dbt_duckdb'
version: '1.0.0'
config-version: 2
profile: 'dbt_duckdb'
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]
clean-targets:
- "target"
- "dbt_packages"
models:
woody_dbt_duckdb:
silver:
schema: silver
materialized: table
gold:
schema: gold
materialized: table
dbt_duckdb:
outputs:
dev:
type: duckdb
path: dbt.duckdb
target: dev
설정을 마쳤으면, 확인을 위해 dbt run
커맨드로 확인합니다.
Source는 DBT에선 Extract, Load가 이미 된 데이터로, 이미 웨어하우스에 로드되어 있는 데이터셋입니다. DuckDB에서 진행하고 있으니, 가볍게 공공데이터 csv 파일을 가지고 만들어보겠습니다.
공공데이터셋
https://bigdata.seoul.go.kr/data/selectSampleData.do?r_id=P213&sample_data_seq=331
해당 csv 파일을 DuckDB를 실행시켜, 한 테이블로 만들어줍니다.
# 터미널에서 덕디비 실행
duckdb dbt.duckdb
# 브론즈 스키마 생성
create schema bronze
# csv 카피 및 테이블 생성
CREATE TABLE bronze.seoul_bronze AS SELECT * FROM read_csv_auto('/Users/woody/Myspace/dbt-project/dbt_duckdb/data/seoul_raw.csv');
bronze 스키마를 만들었고, 이 bronze 스키마에 seoul_bronze라는 테이블을 만들었습니다.
컬럼이 약 120개 정도 되고, 저희는 silver 레이어에서, 특정 컬럼만 사용할 것이니, 해당 부분을 가공하는 silver model을 만들어보겠습니다.
먼저 models의 silver 폴더에서, schema.yml
파일을 수정합니다.
version: 2
models:
- name: silver.seoul_silver
description: "서울시 소득별 및 이동현황 중간 가공 데이터"
sources:
- name: bronze
description: "원본 데이터"
tables:
- name: seoul_bronze
description : "서울시 소득별 및 이동현황 RAW 데이터"
sources는 방금 만든 bronze
스키마의 seoul_bronze
를 사용할 것이고, 이 소스를 사용해서, 데이터를 가공합니다. 가공 로직은 seoul_silver.sql
에 담습니다. sources
의 name
에는 스키마가 들어갔지만, model
은 바로 name
에 스키마와 테이블명이 모두 사용됩니다.
with source_data as (
select
자치구명,
datepart('year', today()) - 생년월일 as 나이,
직업군,
세대주여부,
CAST(추정연소득 AS FLOAT) as 추정연소득,
순자산평가금액,
nullif(평균_통화량, 'NA') as 평균_통화량
from {{ source('bronze', 'seoul_bronze') }}
where 추정연소득 != 'NA'
)
select *
from source_data
{{ source('bronze', 'seoul_bronze') }}
이 부분은 소스의 스키마와 테이블명을 진자템플릿으로 가져오는 부분입니다. 그럼 이렇게 작업을 하고 dbt run
을 해봅니다.
DuckDB에서 확인해보면, 테이블이 잘 생성된 것을 볼 수 있습니다. 스키마가 main_silver인 것을 볼 수 있는데, duckdb-dbt는 models의 경우 main을 추가로 앞에 붙여서 스키마를 생성합니다.
최종 Gold Layer도 크게 다르지 않습니다. 다만 ref 를 이용해서, 실버에 있는 테이블을 참조합니다. 먼저 schema.yml
파일에 저장합니다. 여기선 참조할 source가 없기 때문에, 이렇게 구현합니다.
version: 2
models:
- name: gold.seoul_gold
description: "서울시 소득별 및 이동현황 최종 마트1"
그 다음은 seoul_gold.sql
파일을 생성합니다.
with source_data as (
select
자치구명,
avg(추정연소득) as 평균연소득
from {{ ref('seoul_silver') }}
group by 자치구명
order by 평균연소득 desc
)
select *
from source_data
ref
와 seoul_silver
스키마를 이용해서, 자치구별 평균 연소득을 구해서 테이블을 생성합니다. 그럼 이렇게 작업을 하고 dbt run
을 해봅니다.
Duckdb를 확인해보면, gold 스키마에 데이터가 잘 생성된 것을 확인할 수 있습니다.
dbt docs generate
명령어로 문서를 만들어봅니다.dbt docs serve
프로젝트의 구조와 dbt 프로젝트 내에서 사용중인 데이터베이스의 테이블들을 깔끔하게 볼 수 있습니다.
또한 seoul_silver를 클릭해서, 우측 하단의 초록색 동그라미를 클릭해보면, data lineage를 정확히 확인할 수 있습니다. 업스트림에서 다운스트림으로 이어지는, 데이터 계보를 확인 할 수 있고,
테이블에 대한 정보를 조금 더 보기 쉽게 볼 수 있습니다.
production 환경에서는 반드시 dbt build
를 통해서, 모든 변경사항에 대해서 오류가 없는지 확인하고 모든 실행을 합니다. 여기에는 dbt run
, dbt seed
, dbt test
, dbt snapshot
모든 것들이 포함됩니다. 저희도 기분 낼겸 한번 커맨드를 실행해보겠습니다.
dbt build
dbt seed
를 활용해서, 데이터 가공 로직에 추가할 수 있습니다.dbt test
를 통해서, 데이터의 무결성을 보장할 수 있습니다.dbt snapshot
을 통해서 데이터의 변경사항을 컬럼단위로 관리할 수 있습니다.이 모든 것들은, 에어플로우 스터디가 마치는 대로, 하나의 프로젝트로 소개해드리도록 하겠습니다. 감사합니다:)