上一篇介紹了建立 macro 的情境及如何撰寫,本篇將探討 dbt 內建的 macros。
dbt 提供了眾多內建 macros,大幅提升了代碼的可重用性和維護性。dbt 官方文件列出了完整的內建 macros 清單,並詳細說明了它們的用法。我將介紹幾個在日常工作中最常用、最實用的 macros。
ref 是用來建立 model 間的上下游關聯。例如,計算會員平均交易金額的 model 中使用了會員和交易表,可以用 ref('會員表') 和 ref('交易表') 來表示這兩個表是該 model 的上游表。在執行 dbt run 時,dbt 會先運行會員和交易表,然後才運行計算會員平均交易金額的 model。
透過 ref 建立上下游關係後,後續建立好 dbt docs 就能在其中清楚地看到這三個 models 之間的關聯。
SELECT
m.name,
AVG(t.amount) AS avg_amount
FROM
ref('transactions') t # ref 裡面放 model 名稱
LEFT JOIN
ref('members') m
ON
t.member_id = m.id
GROUP BY
name
ref 回傳值是一個 Relation 物件,包含 database、schema 和 identifier 屬性。因此,在編譯後,dbt 能夠確定 ref 所指的表對應到資料庫中的具體位置。
# members 表放在 db.datamart.members 中
# transactions 表放在 db.datamart.transactions 中
# 上面 model compile 會變以下 query
SELECT
m.name,
AVG(t.amount) AS avg_amount
FROM
`db.datamart.transactions` t
LEFT JOIN
`db.datamart.members` m
ON
t.member_id = m.id
GROUP BY
name
source 和 ref 很相似,但有一個關鍵區別:ref 用於指示 dbt 該 model 依賴哪些上游 model,而 source 則用於指示該 model 使用哪些來源表(需要先在 yaml 文件中定義 source 表)。
通過使用 source 來引用來源表,我們同樣可以建立上下游關係。就能夠利用 dbt docs 來清晰地查看來源表與 model 之間的關聯。
# source.yml
version: 2
sources:
- name: mysql # source 名稱
schema: mysql
database: db
tables:
- name: members
- name: transactions
SELECT
...
FROM
{{ source('mysql', 'members') }} # 第一個參數填入 source 名稱,第二個參數填入表名稱
編譯時,dbt 會根據 source.yml 檔案中指定的 schema 和 database 來構建出來源表在資料倉儲中的完整名稱。
# 編譯結果
SELECT
...
FROM
`db.mysql.members`
config 可以在 model 中設定該 model 的 database, schema, alias, materialized 等屬性(會覆蓋掉在 dbt_project.yml 的設定),詳細可設定的參數和不同層級 config 設定可參考 dbt 文件。
config macro 可以根據 model 的 materialized 填入額外參數(未來提到 materialization 會更詳細說明),例如 model materialized 設為 incremental,config 可以多填入 unique_key 參數(incremental 的選填參數),unique_key 用途可參考 incremental 說明,這邊就不多贅述。
{{
config(
materialized='incremental', # 定義 model materialized 類型
unique_key='date_day' # incremental 的選填參數
)
}}
select
date_trunc('day', event_at) as date_day,
count(distinct user_id) as daily_active_users
from {{ ref('app_data_events') }}
{% if is_incremental() %}
where date_day >= (select coalesce(max(event_time), '1900-01-01') from {{ this }})
{% endif %}
group by 1
以上介紹了 3 個常用 dbt 內建 macro,下篇會繼續介紹內建 macro 以及如何根據使用情境來改寫。