Program
Dalam artikel ini, saya menguraikan beberapa teknik yang dapat membantu mempelajari dbt serta merapikan penyiapan proyek dan pemodelan data, sehingga proses keseluruhan menjadi lebih mudah dikelola.
Selain itu, saya akan membahas pola desain proyek dbt spesifik yang saya andalkan dalam pekerjaan sehari-hari. Metode ini terbukti sangat berharga dalam upaya saya membangun platform data dan gudang data yang akurat, intuitif, mudah dinavigasi, dan ramah pengguna.
Menerapkan pendekatan-pendekatan ini memudahkan pembuatan platform data yang memenuhi standar kualitas tinggi sambil meminimalkan potensi masalah, yang pada akhirnya mengarah ke proyek berbasis data yang lebih sukses.
Apa itu dbt?
dbt (Data Build Tool) adalah solusi open-source yang kuat yang dirancang khusus untuk pemodelan data, memanfaatkan templat SQL dan fungsi ref() (referensi) untuk membangun relasi antar berbagai instance basis data seperti tabel, view, skema, dan lainnya. Fleksibilitasnya cocok bagi mereka yang mengikuti prinsip DRY (Do Not Repeat Yourself).
Dengan dbt, Anda dapat membuat satu templat SQL yang dapat digunakan ulang dan mudah disesuaikan dengan berbagai lingkungan data. Setelah templat ditulis, templat tersebut dapat "dikompilasi" untuk menghasilkan kueri SQL yang diperlukan untuk dieksekusi di setiap lingkungan spesifik.
Pendekatan yang diikuti dbt meningkatkan efisiensi dan memastikan konsistensi di berbagai tahap pipeline data, mengurangi redundansi dan potensi kesalahan sekaligus menyederhanakan proses pemeliharaan dan penskalaan infrastruktur data.
Pemodelan data memainkan peran sentral dalam data engineering, dan dbt adalah alat yang sangat baik. Bahkan, saya berpendapat bahwa menguasai dbt benar-benar penting bagi siapa pun yang ingin menjadi profesional data yang sukses!
Pertimbangkan templat dbt di bawah ini. Ini adalah definisi tabel sederhana, tetapi memuat metadata yang memberi tahu pengguna basis data dan skema mana yang digunakan:
/*
models/example/table_a.sql
Welcome to your first dbt model!
Did you know that you can also configure models directly within SQL files?
This will override configurations stated in dbt_project.yml
Try changing "table" to "view" below
*/
{{ config(
materialized='table',
alias='table_a',
schema='events',
tags=["example"]
) }}
select
1 as id
, 'Some comments' as comments
union all
2 as id
, 'Some comments' as comments
Bayangkan bahwa di hilir, dalam pipeline data, kita memiliki sebuah view yang berasal dari tabel (table_a.sql) yang kita buat di atas. Jadi, garis keturunan pipeline data kita akan terlihat seperti ini:

Contoh garis keturunan pipeline data. Gambar oleh Penulis.
Kita akan menggunakan fungsi ref() untuk menghubungkan dua tahap pipeline kita, dan dalam kasus kita, table_b.sql dapat didefinisikan seperti berikut:
-- models/example/table_b.sql
-- Use the ref function to select from other models
{{ config(
materialized='view',
tags=["example"],
schema='events'
) }}
select *
from {{ ref('table_a') }}
where id = 1
Fungsi ref() memberi tahu bahwa model table_b berada setelah table_a (downstream). Sekarang kita dapat menjalankan pipeline secara keseluruhan menggunakan satu perintah dbt: dbt run --select tag:example.
Berkat kemampuan kode yang dapat digunakan ulang, dbt menyediakan fitur-fitur yang menjadikannya alat yang sangat baik untuk mengelola dan mengoptimalkan alur kerja data di berbagai lingkungan data (produksi, pengembangan, pengujian, dll.).
Selain itu, salah satu kemampuan intinya adalah secara otomatis menghasilkan dokumentasi SQL yang komprehensif, yang secara signifikan meningkatkan transparansi dan memudahkan pemahaman model data bagi pengembang data dan pemangku kepentingan bisnis.
Salah satu tantangan dalam area pemodelan data adalah membangun pipeline transformasi SQL yang kompleks dan melibatkan banyak lapisan sambil membuat kode Anda dapat digunakan ulang. Pipeline ini memerlukan pemikiran yang matang dan pengujian yang cermat untuk memastikan pipeline berfungsi efisien dan menjaga transparansi organisasi agar semua orang dapat memahami logikanya. dbt juga dapat membantu dalam hal ini.
Selain itu, dbt mendukung uji kualitas data dan unit test untuk logika SQL, memungkinkan Anda memvalidasi akurasi dan keandalan transformasi secara terstruktur dan terotomatisasi (workflow CI/CD).
Fitur kunci lainnya adalah otomatisasi yang fleksibel menggunakan macro, yang memungkinkan potongan kode yang dapat disesuaikan dan digunakan ulang, merampingkan tugas kompleks dan meningkatkan produktivitas.
Kombinasi fungsionalitas ini menjadikan dbt solusi ideal untuk menangani tugas terkait SQL dan berbagai lingkungan data, mulai dari memastikan integritas data hingga mengotomatisasi proses berulang, semuanya sambil menjaga efisiensi dan skalabilitas.
Mari praktik langsung dan menjalankan beberapa contoh dengan dbt dan BigQuery sebagai platform data!
Menginstal dan Menyiapkan dbt
Untuk tutorial ini, kita akan menggunakan Google Cloud BigQuery sebagai solusi gudang data. Paket gratisnya menjadikannya kandidat sempurna untuk belajar. Anda dapat mengaktifkan BigQuery di akun Google Cloud Anda.
Kita akan menginstal dbt secara lokal menggunakan Python dan pengelola pip, membuat lingkungan virtual, dan mulai menjalankan model serta pengujian contoh.
Jalankan perintah berikut di baris perintah Anda:
pip install virtualenv
mkdir dbt
cd dbt
virtualenv dbt_env -p python3.9
source dbt_env/bin/activate
pip install -r requirements.txt
Berkas requirements.txt kita harus memuat dependensi berikut:
dbt-core==1.8.6
dbt-bigquery==1.8.2
dbt-extractor==0.5.1
dbt-semantic-interfaces==0.5.1
Lalu, untuk sisa tutorial, kita akan melakukan hal berikut:
- Gunakan akun layanan proyek Google untuk menghubungkan dbt ke BigQuery.
- Buat model contoh kita dan jalankan.
- Tambahkan uji kualitas data dan unit test ke model kita.
- Hasilkan dokumentasi.
Mari buat kredensial akun layanan untuk aplikasi dbt kita:
- Buka konsol IAM Google Cloud Anda, dan di bagian “Service Accounts”, buat akun layanan baru dengan izin BigQuery Admin:

Membuat akun layanan untuk BigQuery di Google Cloud. Gambar oleh Penulis.
- Buat kunci JSON baru untuk akun layanan dan simpan di tempat yang aman, karena Anda akan membutuhkannya nanti:

Menyimpan kunci privat akun layanan dalam format JSON. Gambar oleh Penulis.
- Sekarang, jalankan perintah
dbt initdi terminal untuk menginisialisasi proyek dbt kita.
- Ikuti prompt untuk menentukan pengaturan proyek dbt Anda dan tentukan path ke kredensial akun layanan BigQuery.
Setelah selesai menyiapkan, Anda akan mendapatkan pesan seperti ini:
19:18:45 Profile my_dbt written to /Users/mike/.dbt/profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection.
Dan struktur foldernya akan terlihat seperti ini:
.
├── my_dbt
│ ├── README.md
│ ├── analyses
│ ├── dbt_project.yml
│ ├── macros
│ ├── models
│ ├── polybox-data-dev.json
│ ├── seeds
│ ├── snapshots
│ └── tests
├── dbt_env
│ ├── bin
│ ├── lib
│ └── pyvenv.cfg
├── logs
│ └── dbt.log
├── readme.md
└── requirements.txt
Kita dapat melihat bahwa profiles.yml dibuat di folder root mesin lokal kita, namun idealnya kita ingin berkas tersebut berada di folder aplikasi, jadi mari kita pindahkan.
cd my_dbt
touch profiles.yml
Terakhir, mari sesuaikan isi profiles.yml agar mencerminkan nama proyek kita dan menyertakan kredensial akun layanan Google:
my_dbt:
target: dev
outputs:
dev:
type: bigquery
method: service-account-json
project: dbt_bigquery_dev # replace with your-bigquery-project-name
dataset: source
threads: 4 # Must be a value of 1 or greater
# [OPTIONAL_CONFIG](#optional-configurations): VALUE
# These fields come from the service account json keyfile
keyfile_json:
type: service_account
project_id: your-bigquery-project-name-data-dev
private_key_id: bd709bd92708a38ae33abbff0
private_key: "-----BEGIN PRIVATE KEY-----\nMIIEv...
...
...
...q8hw==\n-----END PRIVATE KEY-----\n"
client_email: some@your-bigquery-project-name-data-dev.iam.gserviceaccount.com
client_id: 1234
auth_uri: https://accounts.google.com/o/oauth2/auth
token_uri: https://oauth2.googleapis.com/token
auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs
client_x509_cert_url: https://www.googleapis.com/robot/v1/metadata/x509/educative%40bq-shakhomirov.iam.gserviceaccount.com
Selesai! Kita siap mengompilasi proyek kita.
- Jalankan ini di baris perintah Anda:
export DBT_PROFILES_DIR='.'
dbt compile
Keluaran yang diharapkan kira-kira seperti ini:
(dbt_env) mike@MacBook-Pro my_dbt % dbt compile
19:47:32 Running with dbt=1.8.6
19:47:33 Registered adapter: bigquery=1.8.2
19:47:33 Unable to do partial parsing because saved manifest not found. Starting full parse.
19:47:34 Found 2 models, 4 data tests, 479 macros
19:47:34
19:47:35 Concurrency: 4 threads (target='dev')
Penyiapan proyek awal kita sudah selesai.
Struktur Proyek dbt
Kita ingin merancang proyek dbt dengan cara yang nyaman dan transparan untuk merefleksikan arsitektur gudang data secara jelas.
Saya menyarankan menggunakan templat dan macro dalam proyek dbt Anda serta memasukkan nama basis data kustom untuk memisahkan lingkungan data secara efektif menjadi produksi, pengembangan, dan pengujian.
Pendekatan ini meningkatkan organisasi dan meminimalkan risiko modifikasi yang tidak disengaja di lingkungan yang salah, sehingga meningkatkan pengelolaan data dan stabilitas alur kerja secara keseluruhan. Dengan melakukan ini, kita dapat dengan mudah mengelola dan memelihara lingkungan tersebut, yang membantu memastikan data produksi tetap aman dan tidak tersentuh oleh perubahan eksperimental atau pengujian.
Basis data di lingkungan yang berbeda juga dapat dinamai secara terstruktur dan konsisten menggunakan sufiks yang relevan (_prod, _dev, _test), sehingga lebih mudah membedakan antar lingkungan sekaligus memungkinkan transisi dan deployment yang lebih mulus.

Berbagai lapisan gudang data di lingkungan produksi. Gambar oleh Penulis.
Sebagai contoh, kita dapat memindahkan lapisan model data utama ke konvensi penamaan basis data menggunakan prefiks raw_ dan base_ dalam penamaan basis data:
Schema/Dataset Tanle
RAW_DEV SERVER_DB_1 -- mocked data
RAW_DEV SERVER_DB_2 -- mocked data
RAW_DEV EVENTS -- mocked data
RAW_PROD SERVER_DB_1 -- real production data from pipelines
RAW_PROD SERVER_DB_2 -- real production data from pipelines
RAW_PROD EVENTS -- real production data from pipelines
...
BASE_PROD EVENTS -- enriched data
BASE_DEV EVENTS -- enriched data
...
ANALYTICS_PROD REPORTING -- materialized queries and aggregates
ANALYTICS_DEV REPORTING
ANALYTICS_PROD AD_HOC -- ad-hoc queries and views
Untuk menyuntikkan nama basis data kustom ini secara dinamis, Anda hanya perlu membuat macro dbt yang menangani tugas ini secara otomatis. Dengan memanfaatkan pendekatan ini, Anda dapat memastikan bahwa nama basis data yang benar digunakan di lingkungan data yang sesuai tanpa perlu mengedit konfigurasi secara manual setiap saat.
Mari lihat potongan kode di bawah, yang memuat macro untuk menetapkan skema yang berbeda tergantung pada lingkungan tempat kita berada:
-- cd my_dbt
-- ./macros/generate_schema_name.sql
{% macro generate_schema_name(custom_schema_name, node) -%}
{%- set default_schema = target.schema -%}
{%- if custom_schema_name is none -%}
{{ default_schema }}
{%- else -%}
{{ custom_schema_name | trim }}
{%- endif -%}
{%- endmacro %}
Sekarang, setiap kali kita mengompilasi model, dbt akan otomatis menerapkan nama basis data kustom berdasarkan konfigurasi yang ditentukan dalam penyiapan setiap model. Ini berarti nama basis data yang benar akan disuntikkan selama proses kompilasi, memastikan model selaras dengan lingkungan yang sesuai — produksi, pengembangan, atau pengujian.
Dengan mengadopsi fitur ini, kita tidak perlu lagi melakukan perubahan manual pada nama basis data, sehingga semakin meningkatkan efisiensi dan akurasi alur kerja kita.
Konfigurasi yang diperlukan ini dapat diatur di properties.yml untuk model kita:
# my_dbt/models/example/properties.yml
version: 2
models:
- name: table_a
config:
description: "A starter dbt model"
schema: |
{%- if target.name == "dev" -%} raw_dev
{%- elif target.name == "prod" -%} raw_prod
{%- elif target.name == "test" -%} raw_test
{%- else -%} invalid_database
{%- endif -%}
columns:
- name: id
description: "The primary key for this table"
tests:
- unique
- not_null
- name: table_b
config:
description: "A starter dbt model"
schema: |
{%- if target.name == "dev" -%} analytics_dev
{%- elif target.name == "prod" -%} analytics_prod
{%- elif target.name == "test" -%} analytics_test
{%- else -%} invalid_database
{%- endif -%}
columns:
- name: id
description: "The primary key for this table"
tests:
- unique
- not_null
Seperti yang Anda lihat, kita dapat menggunakan pernyataan kondisional dasar untuk memasukkan logika ke dalam berkas konfigurasi, berkat dukungan Jinja pada dbt.
Macro tidak dapat digunakan dalam konteks ini, tetapi kita dapat menggunakan kondisional sederhana dengan ekspresi Jinja di dalam berkas .yml. Ekspresi ini perlu diapit tanda kutip. Ini memastikan bahasa templating diinterpretasikan dengan benar saat eksekusi.
Mari jalankan perintah dbt compile dan lihat hasilnya:
(dbt_env) mike@Mikes-MacBook-Pro my_dbt % dbt compile -s table_b -t prod
18:43:43 Running with dbt=1.8.6
18:43:44 Registered adapter: bigquery=1.8.2
18:43:44 Unable to do partial parsing because config vars, config profile, or config target have changed
18:43:45 Found 2 models, 480 macros
18:43:45
18:43:46 Concurrency: 4 threads (target='prod')
18:43:46
18:43:46 Compiled node 'table_b' is:
-- Use the ref function to select from other models
select *
from dbt_bigquery_dev.raw_prod.table_a
where id = 1
Bekerja dengan variabel di dbt
dbt mendukung variabel, yang merupakan fitur kustomisasi yang sangat kuat. Variabel dapat digunakan baik di templat SQL maupun macro, dan dapat dipasok dari baris perintah seperti ini:
dbt run -m table_b -t dev --vars '{my_var: my_value}'
Variabel harus dideklarasikan di berkas proyek utama dbt_project.yml. Contohnya, potongan di bawah menunjukkan caranya:
name: 'my_dbt'
version: '1.0.0'
config-version: 2
...
...
...
# In this example config, we tell dbt to build all models in the example/
# directory as views. These settings can be overridden in the individual model
# files using the {{ config(...) }} macro.
models:
polybox_dbt:
# Config indicated by + and applies to all files under models/example/
example:
# +materialized: view
# schema: |
# {%- if target.name == "dev" -%} analytics_dev_mike
# {%- elif target.name == "prod" -%} analytics_prod
# {%- elif target.name == "test" -%} analytics_test
# {%- else -%} invalid_database
# {%- endif -%}
vars:
my_var: ""
Mari gunakan variabel untuk membuat nama tabel kustom (nama alias) di dbt.
Jika tidak ada alias, nama asli model (nama berkas) digunakan sebagai alias secara default. Logika sederhana ini memastikan bahwa model direferensikan oleh alias yang dikonfigurasi atau nama defaultnya, bergantung pada pengaturan. Implementasi untuk fungsionalitas ini terlihat seperti berikut, memastikan fleksibilitas dalam penamaan dan referensi model di berbagai lingkungan:
-- get_custom_alias.sql
{% macro generate_alias_name(custom_alias_name=none, node=none) -%}
{%- if custom_alias_name -%}
{{ custom_alias_name | trim }}
{%- elif node.version -%}
{{ return(node.name ~ "_v" ~ (node.version | replace(".", "_"))) }}
{%- else -%}
{{ node.name }}
{%- endif -%}
{%- endmacro %}
Mari kita timpa perilaku ini menggunakan variabel. Ini adalah pengaturan umum bagi pengembang data untuk mengurangi risiko saling mengganggu saat bekerja di staging (pengembangan).
Kita ingin menambahkan nama pengembang ke semua instance basis data (tabel, view, dll.) yang dibuat oleh engineer pengembangan.
Mari buat macro generate_alias_name.sql:
--my_dbt/macros/generate_alias_name.sql
{% macro generate_alias_name(custom_alias_name=none, node=none) -%}
{% set apply_alias_suffix = var('apply_alias_suffix') %}
{%- if custom_alias_name -%}
{{ custom_alias_name }}{{ apply_alias_suffix | trim }}
{%- elif node.version -%}
{{ return(node.name ~ "_v" ~ (node.version | replace(".", "_"))) }}
{%- else -%}
{{ node.name }}{{ apply_alias_suffix | trim }}
{%- endif -%}
{%- endmacro %}
Jangan lupa menambahkan variabel baru kita ke dbt_project.yml dan jalankan ini di baris perintah Anda:
$ dbt compile -m table_b -t dev --vars '{apply_alias_suffix: _mike}'
Anda akan melihat keluaran seperti ini:
08:58:06 Running with dbt=1.8.6
08:58:07 Registered adapter: bigquery=1.8.2
08:58:07 Unable to do partial parsing because config vars, config profile, or config target have changed
08:58:07 Unable to do partial parsing because a project config has changed
08:58:08 Found 2 models, 481 macros
08:58:08
08:58:08 Concurrency: 4 threads (target='dev')
08:58:08
08:58:08 Compiled node 'table_b' is:
-- Use the ref function to select from other models
select *
from bigquery-data-dev.raw_dev.table_a_mike
where id = 1
Kita dapat melihat bahwa variabel kita ditambahkan ke nama tabel: table_a_mike.
Lapisan Model Data
Bagian ini membahas bagaimana kita merancang gudang data dalam hal transformasi data. Struktur logis yang disederhanakan dalam dbt dapat terlihat seperti di bawah ini:
.
└── models
└── some_data_source
├── _data_source_model__docs.md
├── _data_source__models.yml
├── _sources.yml -- raw data table declarations
└── base -- base transformations, e.g. JSON to cols
| ├── base_transactions.sql
| └── base_orders.sql
└── analytics -- deeply enriched data prod grade data, QA'ed
├── _analytics__models.yml
├── some_model.sql
└── some_other_model.sql
Secara pribadi, saya selalu berupaya menjaga lapisan model data dasar (base) tetap sesederhana dan sebersih mungkin, memastikan transformasi data hanya diterapkan bila diperlukan. Dengan pendekatan ini, kita bertujuan merancang dan menerapkan lapisan model data base_ yang melibatkan manipulasi data minimal pada tingkat kolom.
Namun, ada kalanya beberapa tingkat manipulasi mungkin bermanfaat, khususnya dalam mengoptimalkan kinerja kueri. Dalam kasus tersebut, penyesuaian kecil di lapisan base dapat meningkatkan efisiensi secara signifikan, sehingga layak menyeimbangkan kesederhanaan dan peningkatan kinerja. Dalam hal ini, menambahkan join tambahan atau filter partisi dapat dibenarkan.
Praktik yang direkomendasikan adalah menerapkan teknik-teknik berikut untuk meningkatkan model dan pipeline data Anda:
- Jika diperlukan, gunakan materialisasi persisten dan clustering untuk objek di lapisan akhir
biz_danmart_. Ini dapat membantu meningkatkan kinerja dan memastikan logika bisnis dikelola secara efisien. - Hindari menggunakan Google Sheets sebagai sumber data. Keterbatasannya dalam menangani dataset besar dapat menimbulkan inkonsistensi dan hambatan kinerja.
- Saya menyarankan menggunakan pembaruan inkremental dengan clustering dan predikat inkremental.
- Hindari pola dengan
select *dan pertimbangkan untuk membagi berkas SQL yang panjang dan kompleks menjadi model yang lebih kecil dengan unit test. - Usahakan untuk tidak menggunakan dbt seeds, karena hanya mendukung berkas CSV dan kurang ideal untuk mengisi tabel di basis data Anda.
- Sebagai gantinya, pertimbangkan melakukan seeding tabel basis data uji melalui materialisasi kustom. Misalnya, sebuah kueri SQL dapat menghasilkan output yang dapat direferensikan di model lain. Pendekatan ini memastikan tabel Anda terwakili dengan baik dalam grafik garis keturunan data, memberikan visibilitas dan pelacakan yang lebih baik dalam infrastruktur data Anda.
Perhatikan kueri SQL di bawah ini. Kueri ini menjelaskan cara membuat materialisasi kustom seperti itu:
-- my_dbt/macros/operation.sql
{%- materialization operation, default -%}
{%- set identifier = model['alias'] -%}
{%- set target_relation = api.Relation.create(
identifier=identifier, schema=schema, database=database,
type='table') -%}
-- ... setup database ...
-- ... run pre-hooks...
-- build model
{% call statement('main') -%}
{{ run_sql_as_simple_script(target_relation, sql) }}
{%- endcall %}
-- ... run post-hooks ...
-- ... clean up the database...
-- COMMIT happens here
{{ adapter.commit() }}
-- Return the relations created in this materialization
{{ return({'relations': [target_relation]}) }}
{%- endmaterialization -%}
-- my_dbt/macros/operation_helper.sql
{%- macro run_sql_as_simple_script(relation, sql) -%}
{{ log("Creating table " ~ relation) }}
{{ sql }}
{%- endmacro -%}
Sekarang, jika kita menambahkan model tambahan bernama table_c untuk mendemonstrasikan fitur ini, kita dapat menggunakan SQL berikut:
-- my_dbt/models/example/table_c.sql
{{ config(
materialized='operation',
tags=["example"]
) }}
create or replace table {{this.database}}.{{this.schema}}.{{this.name}} (
id int64
,comments string
);
insert into {{this.database}}.{{this.schema}}.{{this.name}} (id, comments)
select
1 as id
, 'Some comments' as comments
union all
select
2 as id
, 'Some comments' as comments
;
Sekarang, jika kita kompilasi, hasilnya akan terlihat seperti skrip SQL:
$ dbt compile -m table_c -t dev
Keluaran:
10:45:24 Running with dbt=1.8.6
10:45:25 Registered adapter: bigquery=1.8.2
10:45:25 Found 3 models, 483 macros
10:45:25
10:45:26 Concurrency: 4 threads (target='dev')
10:45:26
10:45:26 Compiled node 'table_c' is:
-- Use the ref function to select from other models
create or replace table bigquery-data-dev.source.table_c (
id int64
,comments string
);
insert into bigquery-data-dev.source.table_c (id, comments)
select
1 as id
, 'Some comments' as comments
union all
select
2 as id
, 'Some comments' as comments
;
Keuntungan pendekatan ini adalah kita tidak perlu lagi bergantung pada adapter BigQuery. Jika kita membuat tabel atau view lain yang mereferensikan operasi ini, kita cukup menggunakan fungsi standar ref().
Dengan demikian, table_c akan otomatis dikenali sebagai dependensi dalam garis keturunan data. Ini memudahkan pelacakan bagaimana tabel saling terkait dan memastikan relasi antar model terdokumentasi dengan baik dalam lingkungan data Anda.
Metode ini membantu dalam mengelola dependensi dan memberikan pandangan yang jelas tentang bagaimana data mengalir melalui berbagai tahap, termasuk langkah pemrosesan data yang kompleks yang melibatkan skrip. Ini sangat berguna untuk memelihara pipeline data yang kompleks.

DAG (directed acyclic graph) di dbt menunjukkan dependensi untuk table_b. Gambar oleh Penulis
Sekarang, kita hanya perlu menambahkan table_c ke pipeline kita:
-- models/example/table_b.sql
{{ config(
tags=["example"]
) }}
select *
from {{ ref('table_a') }}
where id = 1
union all
select *
from {{ ref('table_c') }}
where id = 2
-- select 1;
Dokumentasi akan dibuat otomatis jika kita menjalankan perintah berikut di baris perintah!
dbt docs generate
dbt docs serve
Contoh yang lebih lanjut dari proyek data warehousing di dbt dapat terlihat seperti struktur di bawah ini. Struktur ini memuat banyak sumber data dan transformasi melalui berbagai lapisan model (stg, base, mrt, biz) untuk akhirnya menghasilkan model data mart.
└── models
├── int -- only if required and 100% necessary for reusable logic
│ └── finance
│ ├── _int_finance__models.yml
│ └── int_payments_pivoted_to_orders.sql
├── marts -- deeply enriched, QAed data with complex transformations
│ ├── finance
│ │ ├── _finance__models.yml
│ │ ├── orders.sql
│ │ └── payments.sql
│ └── marketing
│ ├── _marketing__models.yml
│ └── customers.sql
└── src (or staging) -- raw data with basic transformations applied
├── some_data_source
│ ├── _data_source_model__docs.md
│ ├── _data_source__models.yml
│ ├── _sources.yml
│ └── base
│ ├── base_transactions.sql
│ └── base_orders.sql
└── another_data_source
├── _data_source_model__docs.md
├── _data_source__models.yml
├── _sources.yml
└── base
├── base_marketing.sql
└── base_events.sql
Unit Test untuk Logika Model
Unit testing adalah langkah krusial dalam proses pipeline data, di mana kita dapat menjalankan pengujian untuk memvalidasi logika di balik model data kita. Seperti Anda melakukan unit test untuk fungsi Python Anda guna memastikan perilakunya sesuai harapan, saya menerapkan pendekatan serupa untuk menguji model data.
Dengan menjalankan pengujian ini, kita dapat menemukan potensi masalah sejak dini dan memastikan transformasi serta logika berjalan dengan benar. Praktik ini membantu menjaga kualitas data dan mencegah kesalahan menyebar melalui pipeline, sehingga menjadi aspek vital dalam proses data engineering.
Kita dapat menambahkan unit test untuk sebuah model cukup dengan memodifikasi berkas properties.yml:
# my_dbt/models/example/properties.yml
version: 2
models:
...
unit_tests: # dbt test --select "table_b,test_type:unit"
- name: test_table_b
description: "Check my table_b logic captures all records from table_a and table_c."
model: table_b
given:
- input: ref('table_a')
rows:
- {id: 1, comments: 'Some comments'}
- {id: 2, comments: 'Some comments'}
- input: ref('table_c')
rows:
- {id: 1, comments: 'Some comments'}
- {id: 2, comments: 'Some comments'}
expect:
rows:
- {id: 1, comments: 'Some comments'}
- {id: 2, comments: 'Some comments'}
Sekarang, jika kita menjalankan perintah dbt test di baris perintah, kita dapat mengeksekusi unit test:
% dbt test --select "table_b,test_type:unit"
Keluaran ini:
11:33:05 Running with dbt=1.8.6
11:33:06 Registered adapter: bigquery=1.8.2
11:33:06 Unable to do partial parsing because config vars, config profile, or config target have changed
11:33:07 Found 3 models, 483 macros, 1 unit test
11:33:07
11:33:07 Concurrency: 4 threads (target='dev')
11:33:07
11:33:07 1 of 1 START unit_test table_b::test_table_b ................................... [RUN]
11:33:12 1 of 1 PASS table_b::test_table_b .............................................. [PASS in 5.12s]
11:33:12
11:33:12 Finished running 1 unit test in 0 hours 0 minutes and 5.77 seconds (5.77s).
11:33:12
11:33:12 Completed successfully
11:33:12
Coba ubah baris id di expect menjadi 3, dan kita akan mendapatkan galat untuk pengujian yang sama:
11:33:28 Completed with 1 error and 0 warnings:
11:33:28
11:33:28 Failure in unit_test test_table_b (models/example/properties.yml)
11:33:28
actual differs from expected:
@@ ,id,comments
,1 ,Some comments
+++,2 ,Some comments
---,3 ,Some comments
Uji Kualitas Data
dbt juga menyediakan dukungan untuk pemeriksaan kualitas data. Sebelumnya saya menulis tentang hal ini dalam artikel data contracts. Kita dapat memeriksa hampir semua hal yang relevan dengan kualitas data, yakni kebaruan data, kondisi baris, granularitas, dan sebagainya.
Mari lihat lebih dekat model table_b kita. Model ini sudah memiliki beberapa pemeriksaan data:
- name: table_b
config:
description: "A starter dbt model"
schema: |
{%- if target.name == "dev" -%} analytics_dev
{%- elif target.name == "prod" -%} analytics_prod
{%- elif target.name == "test" -%} analytics_test
{%- else -%} invalid_database
{%- endif -%}
columns:
- name: id
description: "The primary key for this table"
tests:
- unique
- not_null
Di sini, di bawah definisi tests, kita menguji table_b.id yang termaterialisasi untuk kondisi unique dan not_null. Untuk menjalankan uji spesifik ini, perintah berikut akan berfungsi:
dbt test -s table_b
Kita juga dapat menguji dataset kita untuk integritas referensial. Ini penting saat bekerja dengan model data yang memiliki join, karena memastikan relasi antar entitas dipertahankan secara akurat. Pengujian ini membantu mendefinisikan bagaimana entitas berbeda, seperti tabel atau kolom, saling berelasi.
Sebagai contoh, perhatikan kode dbt di bawah ini, yang menggambarkan bagaimana setiap refunds.refund_id ditautkan ke transactions.id yang valid. Pemetaan ini memastikan semua refund terkait dengan transaksi yang sah, menjaga integritas data Anda dan mencegah rekaman yatim piatu atau relasi yang tidak konsisten dalam model data Anda:
- name: refunds
enabled: true
description: An incremental table
columns:
- name: refund_id
tests:
- relationships:
tags: ['relationship']
to: ref('transactions')
field: id
Persyaratan data sering kali melibatkan penetapan ekspektasi kapan data baru harus tersedia dan menentukan batas keterlambatan maksimum untuk pembaruan. Pemeriksaan ini penting untuk memastikan data tetap relevan untuk analisis (mutakhir).
Di dbt, ini dapat diterapkan dengan memanfaatkan freshness test, yang memungkinkan Anda memantau apakah data baru tiba dalam kerangka waktu yang diharapkan.
Sebagai contoh, Anda dapat mengonfigurasi freshness test untuk memverifikasi bahwa rekaman terbaru dalam sebuah tabel memenuhi kriteria kebaruan yang Anda tetapkan. Ini memastikan pipeline data Anda memberikan pembaruan secara cepat dan konsisten, membantu menjaga keandalan dan akurasi data sambil mematuhi persyaratan sensitif waktu.
Perhatikan potongan kode di bawah. Kode ini menjelaskan cara menyiapkan freshness test di dbt:
# example model
- name: orders
enabled: true
description: A source table declaration
tests:
- dbt_utils.recency: # https://github.com/dbt-labs/dbt-utils#recency-source
tags: ['freshness']
datepart: day
field: timestamp
interval: 1
Semua pengujian dbt ini luar biasa dan sangat berguna dalam pekerjaan sehari-hari data engineer! Pengujian ini membantu menjaga gudang data tetap tertata dan pipeline data konsisten.
Kesimpulan
Membangun solusi gudang data adalah tugas kompleks yang memerlukan perencanaan dan organisasi yang cermat. dbt, sebagai mesin templating, membantu melakukannya secara konsisten.
Dalam artikel ini, saya telah menguraikan beberapa teknik untuk mengorganisasi folder transformasi data dbt guna meningkatkan kejelasan dan kolaborasi. Dengan menyimpan berkas SQL dalam struktur yang logis, kita menciptakan lingkungan yang mudah dijelajahi, bahkan bagi mereka yang baru dalam proyek.
DBT menawarkan beragam fitur untuk semakin merampingkan proses. Misalnya, kita dapat memperkaya templat SQL dengan memasukkan potongan kode yang dapat digunakan ulang melalui macro, variabel, dan konstanta. Berdasarkan pengalaman saya, bila dipadukan dengan praktik infrastructure-as-code, fungsionalitas ini membantu menegakkan workflow CI/CD yang tepat, sehingga mempercepat pengembangan dan deployment secara signifikan.
Jika Anda ingin membawa pengetahuan dbt ke tingkat berikutnya, pertimbangkan untuk mengikuti kursus Introduction to dbt di DataCamp. Ini adalah sumber yang sangat baik yang dapat membantu Anda memulai dengan sukses melalui latihan yang lebih praktis!
FAQs
Bisakah saya menggunakan dbt dengan basis data apa pun?
dbt bekerja dengan berbagai gudang data dan basis data cloud, seperti Snowflake, BigQuery, Redshift, dan PostgreSQL. Setiap basis data yang didukung memiliki adapter-nya sendiri, yang perlu Anda instal secara terpisah.
Apakah saya perlu keterampilan pemrograman untuk menggunakan dbt?
Pengetahuan dasar SQL sangat penting karena dbt berfokus pada transformasi berbasis SQL. Keterampilan lanjutan, seperti Python, dapat meningkatkan fungsionalitas dbt, terutama saat Anda bekerja dengan ekstensi dbt atau mengotomatisasi workflow.
Apakah dbt hanya untuk gudang data berbasis cloud?
Walaupun dbt paling umum digunakan dengan gudang data berbasis cloud, alat ini juga berfungsi dengan basis data on-premise. Namun, gudang cloud menyediakan solusi yang lebih skalabel, yang sangat dilengkapi oleh dbt.
Bisakah dbt diintegrasikan ke dalam workflow CI/CD?
Ya! dbt dirancang untuk bekerja dalam pipeline CI/CD, mendukung otomatisasi, pengujian, dan kontrol versi. Alat seperti GitHub Actions atau Jenkins dapat mengintegrasikan dbt ke dalam workflow CI/CD, memastikan pengujian dan deployment model data yang andal.
Bisakah dbt digunakan untuk data streaming?
dbt terutama dirancang untuk pemrosesan batch, bukan data streaming. Namun, untuk kebutuhan mendekati real-time, Anda dapat mengombinasikan dbt dengan model inkremental yang memperbarui data secara berkala, bergantung pada kebutuhan kebaruan.
Apa perbedaan antara dbt Cloud dan dbt Core?
dbt Core adalah versi dbt gratis dan open-source, yang dapat Anda jalankan secara lokal atau di lingkungan cloud Anda sendiri. dbt Cloud, layanan terkelola, mencakup fitur tambahan seperti antarmuka pengguna, penjadwalan job, dan integrasi Git, yang dapat bermanfaat untuk kolaborasi tim.
Bisakah dbt bekerja dengan transformasi non-SQL?
dbt berfokus pada transformasi SQL, sehingga transformasi non-SQL tidak didukung secara native. Namun, modularitas dbt memungkinkan integrasi dengan alat eksternal, dan Anda dapat menyertakan skrip kustom jika diperlukan pemrosesan yang lebih kompleks.
Berfokus pada ranah digital dan penuh semangat, saya menikmati tantangan dalam pemasaran digital.
Sebelum pindah ke Inggris, saya mengumpulkan pengalaman lebih dari sepuluh tahun di bidang penjualan, risiko perbankan korporat, dan pemasaran digital, serta mengembangkan keahlian dalam manajemen risiko, pemodelan matematika, analisis statistik, administrasi bisnis, dan pemasaran.
Setelah menyelesaikan MBA di Newcastle, saya kini antusias mengejar karier di pemasaran berbasis data, ilmu komputer, atau AI, dengan potensi untuk melanjutkan ke jenjang PhD. Bidang-bidang ini menawarkan penerapan sains yang praktis, pengembangan profesional berkelanjutan, inovasi, dan kesempatan untuk berkontribusi pada industri yang dinamis.

