最近一直在處理資料分析和資料建模的事情,所以接觸了 dbt 等資料分析的工具,國內目前對於 dbt 比較詳細的資料不多,所以打算寫四道五篇 dbt 相關的文章,本文屬於 dbt 系列的第一篇,本篇主要闡述 dbt 一些基本概念,教會你如何設定 dbt 連線遠端資料庫,並執行你的第一個資料模型,那麼本文開始。
DBT(Data Build Tools)是一種資料轉換工作流工具,作為資料分析師,我們需要將原始的資料進行各類加工組合來應對更為複雜的資料分析需求。準確來說,dbt 還是來寫 sql 做各種資料查詢,你可能會想,那我自己寫 sql 不就完事了,還用啥 dbt。事實上,由於資料庫種類繁多,sql 會存在相容問題;其次,資料轉換會存在資料依賴,比如底層原始資料層層轉變為業務資料,你可能需要自己來維護這個依賴關係,其實仔細一想,你就會發現自己做會非常麻煩。
我們可以把 DBT 想象成一個廚師,而原始資料就像是食材。廚師(DBT)的工作就是把食材(原始資料)加工成好吃的菜(有用的資料模型)。這個過程就像是烹飪一樣,需要按照一定的順序和步驟來操作。
DBT 的工作流程就像是烹飪的步驟,我們只需要告訴 DBT 想做什麼菜(即你想要的資料模型是什麼樣的,當然 sql 肯定得自己寫),然後,DBT 會按照你的指示,一步步地處理食材(即處理原始資料),最後做出你想要的菜餚(即生成你需要的資料模型)。
其實說到這,你就能明白 dbt 能讓我們更聚焦在我們想要什麼資料,定義怎樣的資料模型,其餘的工作流全權交給 dbt 即可,這就是 dbt 的作用。
我們在 dbt 檔案開頭會留意到兩個比較重要的名詞,dbt core 和 dbt cloud,新手可能已經不知道該從哪個入手了,這裡先解釋下區別:
dbt Core
是 dbt
的開源部分,它提供了資料建模、轉換和管理的核心功能。使用 dbt Core
,你可以定義和執行資料轉換模型,生成 SQL 查詢,並將資料寫入目標資料倉儲(如BigQuery、Snowflake等)。總而言之,你接下來要使用的 dbt 命令都是基於 dbt core,所以這個必須安裝(後面細說)。dbt Cloud
是 dbt
的雲服務,構建在 dbt Core
的基礎之上。它提供了託管服務,CI/CD 部署以及圖形化的使用者介面,能讓你直接在平臺執行 dbt
模型而無需自己設定和搭建基礎設施,關於 dbt cloud 我後續單獨出一篇文章。總而言之,就是 saas 付費服務和開源在地化自行搭建的區別,那麼本文自然是從 dbt core 的視角出發了。
除了 dbt core,第二個重要的概念是 dbt adapters,也就是 dbt 介面卡,而且我們要做資料處理一定是安裝 dbt core + 某個資料庫所對應的介面卡。
大家都知道不同的資料庫在 SQL 查詢上都會有些許差異,要記住所有型別的特定語法成本高但收益低,介面卡正好幫我們做了這件事,介面卡的作用之一是提供一種標準化的介面,讓你可以使用相同的 SQL 語法來與不同的底層資料平臺互動,而不需要關注 SQL 語句本身。
dbt 本身提供的介面卡就非常多,除了官網維護的介面卡之外,還有社群自行維護且受 dbt 官方認可的介面卡,所以從資料平臺(比如 bigQuery、Postgres)到資料庫(比如 mysql)本身。
dbt 為所有的介面卡都提供了獨立的檔案,以及設定說明,大家根據自己的資料庫型別可以直接來這個檔案目錄搜尋檢視即可。
ELT 和 ETL 是兩種常見的資料分析模式,它們在資料處理流程中的步驟順序上有所不同。
ETL:
在 ETL 模式中,資料在提取後經過一系列複雜的轉換操作,然後再載入到目標系統。這種模式適用於需要對資料進行多次、複雜轉換的情況,比如將多個源的資料合併,進行聚合等。
ELT(提取、載入、轉換):
顧名思義,在資料處理順序上有所不同。ELT 模式中,資料首先載入到目標系統,然後在目標系統內進行轉換。這種模式適用於目標系統有足夠計算資源的情況,可以在目標系統中直接處理原始資料。
兩者區別:
理解 ELT(Extract, Load, Transform)和 ETL(Extract, Transform, Load)的概念有助於更好地理解這三個工具在資料處理和分析中的角色。
整體流程:
這種結合 ELT 和 ETL 的方式,利用了 Fivetran 的強巨量資料載入能力,同時通過 dbt 提供的資料建模工具,實現了靈活而可維護的資料處理和分析流程。
綜合考慮,Fivetran 和 dbt 可以協同工作。Fivetran 負責將資料從源頭搬移到資料倉儲,而 dbt 則負責在資料倉儲中進行進一步的處理和建模,以便更輕鬆地進行復雜的查詢和分析。簡單理解,Fivetran 只提供了基礎的資料淨化和轉換,而 dbt 提供更專業更強大更自由的資料轉換。
與 npm 需要依賴 node 一樣,pip 命令也需要安裝 Python,關於版本這裡推薦安裝 3.8 3.9 即可,不要安裝 3.10。我在安裝了 Python 3.10 後出現了安裝 mysql 介面卡和 core 包時,一直只能安裝 0.19.2 的情況,而 core 最新的版本都到了1.1.6,導致我一直陷入了包版本是對的,但是 core 與 mysql 介面卡依賴包版本錯誤需要解決版本衝突的怪圈中,這點切記。
上文已經提到 dbt core 屬於 dbt 的開源核心,我們後續使用的命令都由這個包提供。安裝 dbt core 的方式有很多,官方支援 pip、docker、homebrew 等等。
上文我們已經安裝了 Python ,所以我們在終端執行如下命令即可:
pip install dbt-core
dbt 預設全域性安裝,所以即便你在某個專案路徑下,它還是會基於全域性安裝,在安裝完成之後,我們能執行如下命令檢查安裝是否完成。
pip show dbt-core
比如我安裝的就是 core 1.1.6 版本,這裡就能看到安裝的版本,路徑等相關資訊。
我們後續所有工作,都將基於 core 與 adapters 兩個包來完成,其實準備來說,當我們執行安裝某個介面卡時,這個命令會預設安裝與之關聯的 core 包,也就是一個命令自動安裝兩個包,這裡我們以 bigQuery 為例:
pip install dbt-bigquery
同理,安裝之後可以執行命令檢查安裝包的版本等資訊:
pip show dbt-bigquery
某些情況下,你先執行了下載介面卡的命令,會預設幫你 core 包,你也許想單獨再安裝更高版本的 core 包,你可以通過解除安裝重灌的形式來完成,比如:
## 先解除安裝
pip uninstall dbt-core
## 再安裝執行版本包
pip install dbt-core==1.1.6
以上就是 dbt 兩個核心的包了,我們只需要安裝這兩個包就能支撐接下來的所有工作,再做個總結,解釋下兩個包的作用:
可能到這裡,大家覺得安裝完介面卡以及dbt core 就已經夠了,然後我們在終端直接通過命令連結資料庫進行操作,其實不是的。我們需要初始化一個專案,而且我們還需要在專案中編寫資料模型語句,以及一些基本的設定程式碼。
初始化一個 dbt 專案有兩種方式,第一種是直接通過命令:
## 你可以在你的專案目錄下執行
dbt init
之後 dbt 會幫你建立一個模版專案,假設你出現了 dbt 命令不存在的報錯,那麼就是你的 dbt core 包沒安裝好,你應該重新走上文的命令,以及通過 pip show dbt-core
來檢查你的 core 版本資訊。
除了命令,其實我更推薦使用官網的模版專案,因為 dbt 命令除了資料做轉化,還包含資料寫入資料庫的命令,而 init 建立的模版只是最基礎的模版,不包含模擬資料,也不包含模擬的資料模型,一切從零開始還是會存在部分難度。
大家可以直接跳轉 jaffle_shop,然後 git clone
下載本地,之前由於我們已經安裝了 core 和對應的介面卡,所以我們直接拿這個專案練手就好了。
需要注意的是,我第一次使用 dbt init
初始化專案,這個命令很奇怪會在電腦根路徑建立一個profiles.yml
設定,而專案本身就是依賴這個設定來與資料庫建立聯絡。
其實大家應該都想得到,這種核心設定肯定得跟著專案走,全域性即便有也應該會被專案內的設定所覆蓋,結果我在專案根目錄專門建立profiles.yml
後執行命令每次還是走根路徑的設定,此問題可能跟我 dbt 版本有關,暫時解釋不了。
我查閱了官網的說明,官網也確定會優先走專案根目錄的設定,電腦根目錄設定只是起到預設兜底的作用。但假設大家使用 jaffle_shop 專案,因為缺少 init 過程,沒有根目錄建立設定的行為,起碼後續我的命令確實走了專案內的設定。
萬事俱備,現在我們需要連結資料庫,接下來才能做資料轉換的工作,這裡我們以 bigquery 為例。
首先 bigquery 是 Google 的資料平臺,它支援四種連線方式,具體可參考:bigquery setup
這裡我以 Service Account File
的方式來連結。其次,由於 Google 資料庫不支援本地連線,所以我們需要把 clone 的專案整個上傳伺服器,通過遠端來聯調資料庫,前端同學如果不清楚,可以問下伺服器端同學日常開發怎麼做的就好了。
我們需要在之前 clone 的 jaffle_shop 專案下建立 profiles.yml
檔案,之後貼上如下程式碼到檔案即可:
jaffle_shop:
target: dev
outputs:
dev:
type: bigquery
method: service-account
project: demo-data-analytics
dataset: dev_data_statistics
threads: 4 # Must be a value of 1 or greater
keyfile: data-analytics-bef7505.json
首先 jaffle_shop
這個欄位需要跟我們專案根目錄下 dbt_project.yml
中的 profile 屬性欄位相同,你可以取任何名字,但兩邊得保持一致。
target:dbt 專案本身也有分支和環境的區別,現在我們就是學習和測試,所以這裡環境可以定義為 dev 即可。
type:你所使用介面卡所對應的資料庫名稱,因為我們使用的是 bigquery,所以這裡填 bigquery 即可。
method:固定設定,不用改。
project:專案名,注意是你的專案名,當然也可能叫資料容器名,就是最外層的容器名。
dataset:資料集名稱,一般一個資料集下包含多張資料表,所以這個關係就是資料庫---資料集--資料表的關係。但需要注意的是,一般資料庫有N個資料集,我們運算元據也不可能只操作一個資料集,所以這裡的 dataset 只是作為預設值,如果大家有資料庫所有許可權,還是能查詢所有資料集,不過它會影響 dbt seed 資料庫新表的建立位置,一般我們 dataset 提供哪,seed 命令建立的新表就在哪。總而言之,不影響查詢資料轉換,但是影響 seed 和我們 model 新表、檢視建立的位置。
threads:用於指定執行 dbt 任務時的並行執行緒數。使用多個執行緒,可以加快 dbt 流水線的執行速度,這裡我們也預設 4 即可。
keyfile:連結 Google 資料庫也需要授權,簡單理解就是一份祕鑰,因為我的祕鑰也直接放在了專案根路徑,所以我這裡直接引即可。
設定完成後,我們執行 dbt debug
可以檢查專案與資料庫的連結情況,比如:
那麼到這裡,我們成功讓 dbt 專案連結到了遠端資料庫,要做資料分析或者建模,我們肯定得提前往資料庫寫入部分資料然後再基於資料做分析,使用上文提到的 jaffle_shop 模版專案的好處就是,專案直接為我們準備好了資料檔案和模型檔案,現在讓我們執行如下命令:
## 將專案中 scv 資料檔案寫入連線的資料庫
dbt seed
## 執行整個 dbt 專案,開始資料建模
dbt run
在執行完成後,當我們來到資料庫中的 dev_data_statistics 資料集,在此資料集下即可看到 jaffle_shop 中所定義的模型檔案。有一個小技巧,dbt 在資料庫中建立的所有模型名稱都預設是我們的 sql 檔名,這非常方便我們對應查詢表或者檢視。
那麼道理,我們基本走完了一個 dbt 流程,成功設定且執行了屬於我們第一批資料模型。
順帶,我整理了部分 dbt 命令註解:
build
:按照指定的順序執行所有的資料載入、資料模型、資料快照和資料測試。這個命令會編譯 SQL 並執行相應的操作,構建資料倉儲。
clean
:刪除指定的資料夾,通常用於清理生成的檔案或目錄。clone
:建立一個節點的副本,可以在專案中複製和重用節點。這個命令可以幫助你快速建立類似的資料模型。compile
:將 dbt 專案中的程式碼轉換為可執行的 SQL 語句,這個命令可以幫助你檢查和驗證你的程式碼是否正確。debug
:顯示當前 dbt 環境和設定的資訊(上面用過了),這個命令可以幫助你瞭解當前的 dbt 設定和環境變數。deps
:更新專案中使用的依賴項,以獲取最新版本的依賴庫(dbt 也有三方包,後續文章講)。docs
:生成或提供你的專案的檔案網站,這個命令可以幫助你生成和檢視專案的檔案,以便其他人瞭解你的資料模型和操作。init
:初始化一個新的 dbt 專案,這個命令會建立一個新的 dbt 專案,並生成必要的檔案和目錄結構,以便你開始構建資料倉儲。list
:列出專案中的資源,如資料模型、表、檢視等。這個命令可以幫助你檢視專案中的所有資源。parse
:解析專案並提供關於效能的資訊,這個命令可以幫助你瞭解專案的結構和效能,以便進行優化。retry
:重新執行上次執行失敗的節點,這個命令可以幫助你重新執行失敗的資料模型或操作,以解決錯誤。run
:編譯 SQL 並執行指定的資料模型或操作。這個命令用於執行 dbt 專案中的資料模型和操作,以構建資料倉儲。
seed
的主要目的是載入原始、靜態的資料,這些資料通常不需要經常變動,例如國家列表、產品類別等。seed
會負責將這些靜態資料載入到資料庫中,為後續的分析和轉換提供基礎資料。run
的主要目的是執行資料模型,通過執行 SQL 查詢和轉換邏輯,生成新的表、檢視或者其他的資料結構。這些模型可能依賴於 seed
匯入的資料,也可能依賴於其他模型生成的資料。dbt run --models model_name
,或者dbt run --models model1,model2
。dbt run --target dev 或者 prod
run-operation
:執行指定的宏(macro),並傳遞任何提供的引數。這個命令可以幫助你執行自定義的宏,以實現特定的資料處理邏輯。seed
:從 CSV 檔案中載入資料到資料倉儲中。這個命令用於將資料載入到你的資料倉儲中,以供後續的資料模型使用。show
:為指定的資料模型或操作生成可執行的 SQL。這個命令可以幫助你檢視指定資料模型或操作的 SQL 程式碼。snapshot
:執行專案中定義的資料快照操作。這個命令用於執行 dbt 專案中定義的資料快照操作,以捕捉資料的歷史狀態。source
:管理專案的資料來源。這個命令可以幫助你新增、設定和管理專案中的資料來源,以便從不同的資料來源中提取資料。test
:這個命令用於在已部署的資料模型中執行資料測試,以確保資料的準確性和一致性,基本作用:
舉個 test 的例子:
models:
- name: my_model
tests:
- my_test:
severity: error
description: "Check if column X contains null values"
check: "select count(*) from {{ ref('my_model') }} where X is null"
expect: "select 0"
在上面的範例中,my_test
是一個測試用例的名稱,my_model
是模型的名稱。check
查詢語句中使用了 {{ ref('my_model') }}
來參照模型,然後檢查模型中的列 X
是否包含空值。
dbt run
命令預設建立的是檢視(views),但是你可以通過在模型檔案中設定{{ config(materialized='table') }}
來指定dbt run
生成表(tables)而不是檢視,或者在 dbt_ project 設定中對資料夾進行定義。
舉個例子,我們在 dbt 模型檔案頂部新增以下程式碼:
{{ config(materialized='table', sort='timestamp', dist='user_id') }}
-- Your SQL code here
這樣,當我們執行dbt run
命令時,dbt 會建立一個表而不是一個檢視。
關於檢視和表的區別,這裡我給一些比較生硬但明顯的區別:
dbt run
時重新填充。表是資料庫中儲存資料的主要結構。與檢視不同,表會儲存資料。當你查詢表時,你會直接獲取儲存在表中的資料,而不需要重新計算或檢索資料。表的一些特點:
總結起來,檢視和表在用途上可能有很多相似之處,但表是實打實的資料,而檢視是一箇中間態的資料,前者可以CRUD直接操作,而檢視只能查,像修改只能 dbt run 完整更新。
那麼到這裡,第一篇文章結束,第二篇我們詳細聊下 dbt 設定,以及一些更進階的用法,比如區分 dev prod 將模型寫入不同目標資料集等等,關於本文有任何走不通的地方或者疑問環境留言提問。