dbt Analyses 與 Exposures:管理臨時性分析查詢與資料下游依賴

在 dbt 的開發旅程中,我們主要關注的是 Models,那些最終會在資料庫中建立成 Table 或 View 的物件。然而,數據團隊的工作不僅止於建立資料表,我們還經常需要:

  1. 撰寫臨時性的分析 SQL (Ad-hoc queries),這些查詢需要引用現有的 Models,但不需要被寫入資料庫。
  2. 管理資料的「消費者」,例如 BI 儀表板 (Dashboards)、機器學習模型或外部應用程式,並追蹤它們與 dbt Models 的依賴關係。

這兩項需求,分別由 dbt 的 AnalysesExposures 功能來滿足。

dbt Analyses:分析師的強力草稿紙

Analyses 是 dbt 專案中一個專門存放「分析型 SQL」的目錄 (預設為 analyses/)。放在這裡的 SQL 檔案具有以下特性:

  • 支援 Jinja 與 dbt 功能:你可以使用 {{ ref('model_name') }}{{ source(...) }} 以及任何自定義的 Macros。這意味著你的分析查詢可以隨著 Models 的改名或邏輯變更而自動更新,不用手動維護。
  • 版本控制:這些查詢是專案的一部分,可以被 Git 追蹤與管理。
  • 不會被執行 (Materialized):這點最重要。執行 dbt run 時,dbt 不會在資料庫中執行這些 SQL,也不會建立任何 View 或 Table。它們純粹存在於程式碼庫中。
  • 可以被編譯:透過 dbt compile,dbt 會將包含 Jinja 的原始碼解析成可執行的純 SQL。

為什麼需要 Analyses?

在沒有 Analyses 的情況下,分析師通常會把 SQL 存在自己的電腦文件夾或像 Notion 這樣的筆記軟體中。當 dbt model (例如 fct_orders) 修改了欄位名稱,這些散落在各處的 SQL 就會報錯 Fail。

使用 Analyses 的好處:

  1. 單一真理來源:所有依賴 dbt models 的查詢都集中管理。
  2. 便於審查 (Review):複雜的分析邏輯可以透過 Pull Request 讓同事審查,確保邏輯正確。
  3. 測試邏輯:在正式建立 Model 之前,可以先在 Analyses 中撰寫 SQL 驗證邏輯與數據結果。

如何使用 Analyses

假設我們想計算「2023 年每月的營收與訂單數」,這是一個一次性的分析需求,不需要建表。

  1. analyses/ 目錄下建立一個檔案,例如 monthly_revenue_analysis.sql
  2. 撰寫 SQL,並使用 ref() 來引用已經整理好的 Model:
-- analyses/monthly_revenue_analysis.sql

with monthly_data as (
    select
        -- 使用 date_trunc 函數將日期取至月份
        date_trunc('month', order_date) as order_month,
        count(order_id) as total_orders,
        sum(amount) as total_revenue
    from {{ ref('fct_orders') }} -- 引用 fct_orders model
    where status = 'completed'
    group by 1
)

select *
from monthly_data
order by order_month desc
  1. 編譯 SQL:

在終端機執行:

dbt compile
  1. 取得結果:

dbt 會將編譯後的 SQL 檔案輸出到 target/compiled/{project_name}/analyses/monthly_revenue_analysis.sql。 檔案內容會將 {{ ref('fct_orders') }} 替換成實際的資料表名稱 (例如 analytics.dbt_alice.fct_orders)。你可以直接複製這段 SQL 到你的 SQL Client (如 DBeaver) 或 BI 工具中執行。

dbt Exposures:定義資料的下游應用

當你的 dbt 專案日益壯大,擁有數百個 Models 時,一個常見的挑戰是:「如果我修改了 dim_customers 這個 table,會不會弄壞行銷部門的 Looker 報表?」

dbt 本身只知道 Models 之間的依賴關係 (Lineage),但它不知道 dbt 之外的世界。Exposures 就是用來填補這個資訊缺口的。它允許你在 dbt 專案中宣告「外部的下游相依性」,將 Dashboard、ML 模型或反向 ETL 流程納入 dbt 的 Lineage Graph 中。

Exposures 的用途

  1. 影響範圍分析 (Impact Analysis):在修改程式碼前,查看 Lineage Graph 就能知道變更會影響哪些 Dashboard。
  2. 文件化與目錄:讓團隊成員知道數據最終被用在哪裡,以及由誰負責 (Owner)。
  3. 整合應用:某些進階工具 (如 dbt Cloud 的 Dashboard Status Tile) 可以利用這些資訊,直接在 Dashboard 上顯示資料的新鮮度或品質狀態。

如何定義 Exposures

Exposures 定義在 .yml 檔案中 (通常建議放在 models/ 目錄下的相關業務資料夾內,或是獨立的 _exposures.yml 檔案)。

以下是一個完整的 Exposure 定義範例:

version: 2

exposures:
  - name: executive_dashboard
    label: '高階主管營收儀表板' # 在文件中顯示的名稱
    type: dashboard # 類型:dashboard, notebook, analysis, ml, application
    maturity: high # 成熟度:high, medium, low
    url: https://metabase.company.com/dashboard/123
    description: >
      這是 CEO 與 CFO 每週一會議使用的主要報表,
      包含每日營收趨勢與 top 10 產品銷量。

    # 定義依賴關係:這個 Dashboard 用到了哪些 dbt models
    depends_on:
      - ref('fct_orders')
      - ref('dim_customers')
      - ref('dim_products')
      - source('raw_google_analytics', 'traffic') # 也可以依賴 source

    # 定義負責人資訊
    owner:
      name: Data Team
      email: data@company.com

屬性說明

  • type: 描述下游應用的類型,常用的有:
    • dashboard: BI 儀表板 (Tableau, Metabase, Superset 等)。
    • notebook: Jupyter Notebook 或 Hex 等筆記本。
    • application: 網站或後端服務。
    • ml: 機器學習模型。
  • maturity: 描述這個應用的重要程度:
    • high: 關鍵任務,不能隨意壞掉。
    • medium: 重要但非緊急。
    • low: 實驗性質或已棄用。
  • depends_on: 最關鍵的部分,列出此 Exposure 查詢了哪些 ref (Models) 或 source。這建立了連線。
  • owner: 提供聯絡人資訊,當 Model 出問題時知道該通知誰。

在 dbt Docs 中檢視

定義好 Exposure 後,執行 dbt docs generate 並開啟 dbt docs serve。 在 Lineage Graph (血緣關係圖) 中,你會看到最右側出現了橘色的 Exposure 節點。

這讓數據工程師可以清楚地看到:Source -> Staging -> Marts -> Exposure (Dashboard) 的完整資料流向。

總結

特性Analyses (分析)Exposures (暴露/下游)
主要用途寫 Ad-hoc SQL、測試邏輯記錄資料的消費者 (Dashboard 等)
產出物編譯後的 SQL 檔案dbt docs 中的節點與說明
是否建表否 (不會寫入 DB)否 (純 Metadata 定義)
是否可執行需透過 dbt compile 取得 SQL僅作為文件與 Lineage 展示
核心價值讓臨時查詢也享有版控與 Jinja 能力解決資料管道「最後一哩路」的可觀測性

善用這兩個功能,可以讓你的 dbt 專案從單純的「造表工廠」,升級為涵蓋資料探索與下游依賴管理的完整「數據治理平台」。