iT邦幫忙

2024 iThome 鐵人賽

DAY 5
2

上一篇介紹了 ref, source, config 三個內建 macro,本篇繼續介紹內建 macro 以及我們團隊如何根據使用情境來改寫 macro。

generate_alias_name

當 dbt 執行 model 時,會在 warehouse 中創建對應的表,identifier (表名稱) 是根據 model 的 alias,而 alias 預設是用檔案名稱,如果不希望用檔案名稱作為表名稱,有兩種方式可以更改。

  1. 在 model 中設定 config,並填入參數 alias,指定想要的名稱
    #analytics/ga_sessions.sql
    {{
        config(
            alias='sessions'
        )
    }}
    SELECT
     ...
    FROM
     ...
    
  2. 改寫 generate_alias_name:generate_alias_name dbt 內建 macro,用途是來將檔名轉為 alias
    {% 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_schema_name

跟 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。

參考


上一篇
dbt 內建 macros (上)
下一篇
在 dbt 管理 BigQuery UDF (上)
系列文
dbt 修煉之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言