上一篇介紹了 ref, source, config 三個內建 macro,本篇繼續介紹內建 macro 以及我們團隊如何根據使用情境來改寫 macro。
當 dbt 執行 model 時,會在 warehouse 中創建對應的表,identifier (表名稱) 是根據 model 的 alias,而 alias 預設是用檔案名稱,如果不希望用檔案名稱作為表名稱,有兩種方式可以更改。
#analytics/ga_sessions.sql
{{
config(
alias='sessions'
)
}}
SELECT
...
FROM
...
{% macro generate_alias_name(custom_alias_name=none, node=none) -%}
{%- if custom_alias_name -%} # 如果 config 有設定 alias,就會使用 alias 指定名稱
{{ custom_alias_name | trim }}
{%- elif node.version -%}
{{ return(node.name ~ "_v" ~ (node.version | replace(".", "_"))) }}
{%- else -%}
{{ node.name }} # 如果沒有指定就用檔名
{%- endif -%}
{%- endmacro %}
migo 因為是 B2B 公司,會有很多客戶資料,每個客戶都會有會員、交易、點數等等表。
在 BQ 中我們是透過 dataset 來區分客戶,不同 dataset 的會員、交易的表名都一致。但 dbt model 的名稱不能重複,所以我們的 model 檔名會是 {客戶名稱}.{用途}.{表名},例如 A 客戶 datamart 的會員表 model 檔名會叫做 A.datamart.members,就能達到 model 名不重複。
但同時 model 的 alias 就會與 BQ 表名不一致,雖然可以透過 config 設定 alias 來解決,卻會造成每次開發 model 都要額外寫 config。
我們調整過後的表名只有最後一部分是 BQ 的表名,那就可以改寫 generate_alias_name,透過分割檔名取最後一部分來抓到表名,每個 model 在產生 alias 時都會用到 generate_alias_name 這支 macro,就不需要調整每個 model 的 config。
{% macro generate_alias_name(custom_alias_name=none, node=none) -%}
{%- if custom_alias_name is none -%}
# 將檔名透過 . 分隔,再取最後一部分
{% set name_list = node.name.split('.') %}
{{ name_list | last }}
{%- else -%}
# 如果有設定 alias,就不處理
{{ custom_alias_name | trim }}
{%- endif -%}
{%- endmacro %}
跟 generate_alias_name 相似,generate_schema_name 也是 dbt 內建 macro,用途是用來產生 model 的 schema。
{% macro generate_schema_name(custom_schema_name, node) -%}
{%- set default_schema = target.schema -%}
{%- if custom_schema_name is none -%}
{{ default_schema }}
{%- else -%}
{{ default_schema }}_{{ custom_schema_name | trim }}
{%- endif -%}
{%- endmacro %}
原本的 generate_schema_name 會使用在 profiles.yml 中定義的 target schema(詳細說明可參考文件),如果 config 中有額外設定 schema,會在 target schema 後面加底線和額外設定的 schema 名稱。
我們團隊則希望不要有預設的 target schema,各個 folder 所屬的 schema 自行定義在 dbt_project.yml 中,所以改寫 generate_schema_name
{% 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 %}
此外,在改寫既有 model 時,我們希望能先看到這次改動的結果,不要直接改動正式環境表,所以需要有測試環境。
我們測試環境是採用在 BQ 建立 CI 的 dataset,例如原本 dataset 叫做 datamart,測試環境就叫做 datamart_ci,兩者只差在 ci,所以我們就改寫了 generate_schema_name,在 dbt run 時指定 target 來告訴 dbt 現在要在測試環境還是正式環境建表。
{% macro generate_schema_name(custom_schema_name, node) -%}
{{%- set default_schema = target.schema -%}
{%- if custom_schema_name is none -%}
{{ default_schema }}
{%- else -%}
{%- set env = target.name -%}
{%- if env is none -%}
{{ custom_schema_name | trim }}
{%- elif env == "ci" -%}
{{ custom_schema_name | trim }}_ci
{%- else -%}
none
{%- endif -%}
{%- endif -%}
{%- endmacro %}
在執行 dbt run 時,如果希望在測試環境執行,target 指定 ci,就能在測試環境建表
dbt run --select client.datamart.members --target ci
以上就是我們團隊常用以及改寫的 dbt 內建 macro,dbt 還有很多其他內建 macro,有興趣可以看官方文件來了解,接下來會介紹如何用 macro 來管理 BigQuery 的 UDF。