터칭 데이터

데모 Input-Output 본문

Airflow 고급 기능, dbt, Data Catalog

데모 Input-Output

터칭 데이터 2024. 1. 4. 17:19

 

 

 

데모: dbt Models: Input & Output


앞서 내용들을 전체적으로 직접 실행해보자

 

 

 

 

 

 

아까 설치한 learn_dbt 프로젝트로 이동하여 dbt_project.yml 파일을 수정할겁니다.

 

 

 

 

 

 

 

 

 

 

 

마지막 두 줄을 삭제합니다. 예제로 만들어져 우리가 사용하지 않기 때문입니다.

 

삭제 후 저장을 마치고

 

 

 

 

 

 

models 폴더의 example 폴더를 삭제합니다.

 

 

 

 

 

 

 

 

대신 src 폴더를 만들고 src 폴더로 이동한 후 3개의 파일을 만듭니다.

 

 

 

 

 

 

src_user_event.sql

WITH src_user_event AS (
    SELECT * FROM raw_data.user_event
)
SELECT
    user_id,
    datestamp,
    item_id,
    clicked,
    purchased,
    paidamount
FROM
    src_user_event

 

 

 

 

 

src_user_variant.sql

WITH src_user_variant AS (
    SELECT * FROM raw_data.user_variant
)
SELECT 
    user_id,
    variant_id
FROM
    src_user_variant

 

 

 

 

 

src_user_metadata.sql

WITH src_user_metadata AS (
    SELECT * FROM raw_data.user_metadata
)
SELECT 
    user_id,
    age, 
    gender,
    updated_at 
FROM
    src_user_metadata

 

 

 

 

 

 

최종 src 폴더의 모습

 

 

 

 

 

 

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt run

 

learn_dbt 디렉토리에서

 

dbt run 명령을 실행하면 3개의 Input이 만들어집니다.

 

 

 

 

 

 

 

 

 

그리고 models 폴더에 dim과 fact 폴더 2개를 만듭니다.

 

 

 

 

 

 

그리고 dim 디렉토리에 아래와 같은 sql 파일 2개를 만들어주세요.

 

dim_user_variant.sql

WITH src_user_variant AS (
 SELECT * FROM {{ ref('src_user_variant') }}
)
SELECT 
    user_id,
    variant_id
FROM
    src_user_variant

 

 

 

 

dim_user_metadata.sql

WITH src_user_metadata AS (
 SELECT * FROM {{ ref('src_user_metadata') }}
)
SELECT
    user_id,
    age,
    gender,
    updated_at
FROM
    src_user_metadata

 

 

 

 

최종 dim 폴더의 모습

 

 

 

 

 

 

 

 

 

 

 

 

fact 폴더에도 sql 파일 하나를 만들어줍니다.

 

 

fact_user_event.sql

{{
    config(
        materialized = 'incremental',
        on_schema_change='fail'
    )
}}
WITH src_user_event AS (
    SELECT * FROM {{ ref("src_user_event") }}
)
SELECT
    user_id,
    datestamp,
    item_id,
    clicked,
    purchased,
    paidamount
FROM
    src_user_event

 

 

 

fact 폴더의 모습

 

 

 

 

 

 

 

 

 

src, dim, fact 3개의 폴더별로 어떤 형태로 테이블의 포맷을 정할지 laern_dbt 폴더의 dbt_project.yml 파일에 정의하겠습니다.

 

 

 

 

 

우리가 아까 example을 지웠던 최하단부에 위와 같이 적어줍니다.

 

learn_dbt 밑에 models에서 만들어지는 데이터들은 전부 view로 만들어지지만 dim 폴더에서 만들어지는 데이터들은 테이블로 만들겠다는 세팅입니다. dim처럼 materialized: table이 아닌 fact는 데이터들이 view로 만들어집니다.

 

 

 

 

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt compile

07:33:23  Found 6 models, 0 sources, 0 exposures, 0 metrics, 455 macros, 0 groups, 0 semantic models

 

dbt compile 명령으로 6개의 모델이 잡히는 것을 볼 수 있습니다.

 

 

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt run

 

그 다음 dbt run으로 스테이징 테이블로 view 3개가 만들어 졌습니다.

 

dim 테이블들은 table로 physical table로 만들어지고

 

fact 테이블은 incremental model임을 확인할 수 있을겁니다.

 

 

 

 

 

 

 

 

이제 fact 폴더의 fact_user_event.sql 최하단부에

 

 

하이라이트 된 코드를 적어주세요.

(현재 제 VScode에 dbt extension이 설치되어 있지 않아 빨간 줄이 떠 있는데 실행에는 문제가 없습니다.)

 

 

 

 

 

 

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt run

 

그리고 다시 dbt run을 실행합니다.

 

fact 테이블이 incremental update가 되었는지 불분명한 상황이므로 postico와 같은 프로그램의 도움을 받아 원본 테이블인 raw_data.user_event에 새로운 레코드를 적재하고 다시 dbt run을 실행하겠습니다.

 

 

 

 

 

 

 

그 전에 적당한 Redshift 클라이언트 툴에서 아래를 수행합니다.

 

SELECT COUNT(1) FROM (각자 스키마).dim_user_metadata;
-- 10000

SELECT COUNT(1) FROM (각자 스키마).dim_user_variant;
-- 10000

SELECT COUNT(1) FROM (각자 스키마).fact_user_variant;
-- 3892760

 

정말로 COPY가 제대로 되었는지 core table들을 COUNT 해보겠습니다.

 

각각 100000, 100000, 3892760 개의 레코드가 있습니다.

 

 

 

 

그리고 아래와 같이 레코드 하나를 추가합니다.

INSERT INTO raw_data.user_event VALUES (100, '2023-06-10', 100, 1, 0, 0);
SELECT * FROM raw_data.user_event WHERE datestamp = '2023-06-10';

 

 

 

이제 터미널에서 dbt run 실행 후 fact_user_event 테이블에 방금 추가한 레코드가 들어갔는지 확인합니다.

 

 

 

 

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt run

 

성공은 하지만 화면만으로는 아직 알 수가 없습니다.

 

이를 확인할 수 있는 한 가지 방법이 있습니다.

 

 

 

 

 

 

 

learn_dbt/models/fact 뿐만 아니라

 

 

learn_dbt/target/compiled/learn_dbt/models/fact 에도 fact 폴더와 fact_user_event.sql 파일이 존재합니다.

 

 

 

우리가 사용한 jinja template에 값이 실제로 치환되어 들어간 최종 SQL문입니다.

좌측의 {{ ref("src_user_event") }}이 우측에서는 실제 값으로 치환되어 있습니다.

 

그 외에도 WHERE절 역시 실제 값으로 치환되어 있습니다.

 

이제 가장 큰 datestamp를 뽑고 그것보다 더 큰 2023-06-10 레코드 하나만 뽑힐 겁니다.

 

그리고 이 결과가 temporary 테이블에 저장되고 최종적으로 fact 테이블에 insert 됩니다.

 

 

 

 

 

 

 

 

 

 

 

방금 우리가 살펴 본 learn_dbt/target/compiled/learn_dbt/models/fact 말고도

 

learn_dbt/run/compiled/learn_dbt/models/fact에도 fact_user_event.sql이 존재합니다.

 

이 파일을 보면

 

 

incremental update를 위해 tmp131407551524라는 테이블이 하나 생기고 이 테이블의 내용이 최종적으로 fact table에 insert됩니다.

 

 

 

 

 

 

 

 

좀 더 자세한 내용은 

 

learn_dbt/run/compiled/learn_dbt/models/dim 의 dim_user_variant.sql에서 살펴볼 수 있습니다.

 

 

CTAS로 스테이징 테이블의 내용들을 꺼내 최종적으로 dev라는 데이터베이스의 사용자 스키마에 dim_user~tmp 테이블을 만들고 이후 성공한다면 내부적으로 원본 테이블을 삭제하고 이 테이블을 원본의 이름으로 rename하는 방식으로 전개됩니다.

 

 

 

 

 

 

 

 

 

이제 적당한 postico 같은 적당한 Redshift 클라이언트 툴에서

 

SELECT * FROM (각자 스키마).fact_user_event WHERE datestamp='2023-06-10'

 

쿼리를 실행합니다.

 

 

정상적으로 Incremental Update가 이루어졌습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

마지막으로 하나만 더 데모를 해보겠습니다.

 

4가지의 Materialization 종류

 

View

데이터를 자주 사용하지 않는 경우

 

Table

데이터를 반복해서 자주 사용하는 경우

 

Incremental (Table Appends)

Fact 테이블
과거 레코드를 수정할 필요가 없는 경우


Ephemeral (CTE)

한 SELECT에서 자주 사용되는 데이터를 모듈화하는데 사용

 

 

우리는 바로 이전에 스테이징 테이블을 View로 실습했습니다. 사실 View는 잘 사용되지 않습니다. 이번에는 CTE 방식인 Ephemeral을 사용하겠습니다.

 

 

 

 

 

 

learn_dbt/dbt_project.yml에 하이라이트된 코드를 추가해주세요.

 

 

 

 

 

 

 

 

dbt run으로 view를 정말 안 만드는지 메시지를 하나하나 읽어 확인할 수도 있지만

 

더 직관적이고 편리한 확인을 위해 postico에서 3개의 View를 먼저 삭제하겠습니다.

 

DROP VIEW (각자 스키마).src_user_event;
DROP VIEW (각자 스키마).src_user_metadata;
DROP VIEW (각자 스키마).src_user_variant

 

 

 

PS D:\Dev_KDT\dbt\learn_dbt> dbt run

 

모델은 6개를 찾았는데 모델 빌딩은 3개만 이루어집니다.

 

View를 명시적으로 만들지 않고 CTE로 fact와 dim 테이블을 만드는데 임베딩되었기 때문입니다.

 

 

 

 

정말로 그런지 learn_dbt/target/compiled/learn_dbt/models/dim 경로에 dim_user_variant.sql를 보겠습니다.

 

 

바로 이전 실습에서 src에 사용했던 CTE로 select하던 부분이 하이라이트된 부분으로 임베드된 것을 볼 수 있습니다.

 

일반적으로 스테이징 테이블은 View나 Table로 만들 필요가 없으며 CTE(Ephemeral)로 사용하는 것이 일반적입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

최종적으로 dim_user와 analytics_variant_user_daily 테이블을 만들고 끝내겠습니다.

 

models/dims 폴더에

 

dim_user.sql 파일을 만들어

WITH um AS (
    SELECT * FROM {{ ref("dim_user_metadata") }}
), uv AS (
    SELECT * FROM {{ ref("dim_user_variant") }}
)
SELECT
    uv.user_id,
    uv.variant_id,
    um.age,
    um.gender
FROM uv
LEFT JOIN um ON uv.user_id = um.user_id

 

위와 같이 작성합니다.

 

 

 

 

 

 

 

models 폴더에 analytics라는 새로운 폴더를 만들고 이 아래에

 

analytics_variant_user_daily.sql 파일을 만들어

 

WITH u AS (
    SELECT * FROM {{ ref("dim_user") }}
), ue AS (
    SELECT * FROM {{ ref("fact_user_event") }}
)
SELECT
    variant_id,
    ue.user_id,
    datestamp,
    age,
    gender,
    COUNT(DISTINCT item_id) num_of_items, -- 총 impression
    COUNT(DISTINCT CASE WHEN clicked THEN item_id END) num_of_clicks, -- 총 click
    SUM(purchased) num_of_purchases, -- 총 purchase
    SUM(paidamount) revenue -- 총 revenue
FROM ue LEFT JOIN u ON ue.user_id = u.user_id
GROUP by 1, 2, 3, 4, 5

 

위와 같이 작성합니다.

 

 

 

 

이제 dbt run을 실행합니다.

 

그 다음 postico와 같은 툴에서 analytics_variant_user_daily 테이블 내용을 보시면 일별로 사용자들의 행동 내역이 요약되어 있을테고 그 사용자에 따른 속성데이터들도 같이 조회될 것입니다.

 

이를 이용해 A와 B의 퍼포먼스를 비교할 수 있습니다.

 

 

 

 

 

 

'Airflow 고급 기능, dbt, Data Catalog' 카테고리의 다른 글

DBT Sources  (0) 2024.01.05
DBT Seeds  (0) 2024.01.05
DBT - Outnput  (0) 2024.01.04
DBT - Input  (0) 2024.01.04
DBT - 사용 시나리오  (0) 2024.01.04