1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dbt_project_evaluator触ってみたメモ

1
Posted at

dbt_project_evaluator を触ってみたので、その時のメモをここに残す。

dbt_project_evaluator とは

自分の dbt プロジェクトが dbt Labs 公式のベストプラクティスに従っているかを評価してくれる dbt パッケージ。

次の6タイプのルールが用意されている。

Type ルール例
Modeling
  • Source を直接 JOIN に使うのは NG
  • ref() を使わず直接テーブルを参照するのはNG
Testing
  • 主キーのテストがない
  • テストのカバレッジを測定
Documentation
  • ドキュメントのカバレッジを測定
  • descrptionが書かれていない dbt モデルはNG
Structure
  • dbt モデルに適切な接頭辞がついていない
  • dbt モデルが適切なディレクトリ配下にいない
Performance
  • view や ephemeral で materialize されている dbt モデルを 4 つ以上重ねるのはNG
Governance model governance についてのルールが用意されている

参考: dbt_project_evaluator

導入方法

dbt_project_evaluator の Package Hub ページの Installation のとおり。

参考: dbt - Package hub

packages.yml に以下を追加。

packages.yml
packages:
  - package: dbt-labs/dbt_project_evaluator
    version: 1.2.4

dbt deps を実行してインストール。

なお、筆者は下記の環境で動かした。

pyproject.toml
[project]
requires-python = ">=3.13"
dependencies = [
    "dbt-bigquery>=1.11.1",
    "dbt-core>=1.11.8",
]

ルールの設定

デフォルト設定だと全てのルールが有効になっている。実運用では、プロジェクトの状況に応じて不要なルールを無効にすることが多いと思われる。

以下に、 Hard Coded Referencesref() を使わずに直接テーブル名を指定していないかを評価するルール)を有効にして、その他のルールを無効にする例を示す。

dbt_project.yml

models:
  dbt_project_evaluator:
    marts:
      dag:
        +enabled: false
        fct_hard_coded_references:
          +enabled: true
      documentation:
        +enabled: false
      governance:
        +enabled: false
      performance:
        +enabled: false
      structure:
        +enabled: false
      tests:
        +enabled: false

参考: Disabling checks - dbt_project_evaluator

挙動

dbt_project_evaluator は次のコマンドを実行することで動かせる。

dbt build --select package:dbt_project_evaluator

挙動は次のとおり:

  1. ルールを評価するための dbt モデルを生成
  2. 生成された dbt モデルに対して dbt テストを実行することで、ルールに沿っているかを評価

例えば、次のような dbt モデルが定義された dbt プロジェクトを考える。

models/example/my_first_dbt_model.sql
{{ config(materialized='table') }}

with source_data as (

    select 1 as id
    union all
    select null as id

)

select *
from source_data
models/example/my_second_dbt_model.sql
select *
from
    -- {{ ref('my_first_dbt_model') }}
    -- わざと Hard Coded References ルールに引っ掛かるようにしてみる
    `YOUR_GC_PROJECT.YOUR_DATASET.my_first_dbt_model`
where id = 1

この dbt プロジェクトに Hard Coded References ルールだけ有効化した dbt_project_evaluator を実行すると、実行ログは次のようになる。

実行ログ
❯ dbt build --select package:dbt_project_evaluator
08:13:07  Running with dbt=1.11.8
08:13:07  Registered adapter: bigquery=1.11.1
08:13:08  Found 21 models, 1 seed, 5 data tests, 722 macros
08:13:08  
08:13:08  Concurrency: 1 threads (target='dev')
08:13:08  
08:13:09  1 of 21 START sql table model YOUR_DATASET.base_exposure_relationships .. [RUN]
08:13:12  1 of 21 OK created sql table model YOUR_DATASET.base_exposure_relationships  [CREATE TABLE (0.0 rows, 0 processed) in 2.39s]
08:13:12  2 of 21 START sql table model YOUR_DATASET.base_metric_relationships .... [RUN]
08:13:14  2 of 21 OK created sql table model YOUR_DATASET.base_metric_relationships  [CREATE TABLE (0.0 rows, 0 processed) in 2.60s]
08:13:14  3 of 21 START sql table model YOUR_DATASET.base_node_columns ............ [RUN]
08:13:18  3 of 21 OK created sql table model YOUR_DATASET.base_node_columns ....... [CREATE TABLE (0.0 rows, 0 processed) in 3.79s]
08:13:18  4 of 21 START sql table model YOUR_DATASET.base_node_relationships ...... [RUN]
08:13:22  4 of 21 OK created sql table model YOUR_DATASET.base_node_relationships . [CREATE TABLE (0.0 rows, 0 processed) in 3.74s]
08:13:22  5 of 21 START sql table model YOUR_DATASET.base_source_columns .......... [RUN]
08:13:24  5 of 21 OK created sql table model YOUR_DATASET.base_source_columns ..... [CREATE TABLE (0.0 rows, 0 processed) in 2.24s]
08:13:24  6 of 21 START sql table model YOUR_DATASET.stg_exposures ................ [RUN]
08:13:26  6 of 21 OK created sql table model YOUR_DATASET.stg_exposures ........... [CREATE TABLE (0.0 rows, 0 processed) in 2.25s]
08:13:26  7 of 21 START sql table model YOUR_DATASET.stg_metrics .................. [RUN]
08:13:28  7 of 21 OK created sql table model YOUR_DATASET.stg_metrics ............. [CREATE TABLE (0.0 rows, 0 processed) in 2.03s]
08:13:28  8 of 21 START sql view model YOUR_DATASET.stg_naming_convention_folders . [RUN]
08:13:29  8 of 21 OK created sql view model YOUR_DATASET.stg_naming_convention_folders  [CREATE VIEW (0 processed) in 0.58s]
08:13:29  9 of 21 START sql view model YOUR_DATASET.stg_naming_convention_prefixes  [RUN]
08:13:30  9 of 21 OK created sql view model YOUR_DATASET.stg_naming_convention_prefixes  [CREATE VIEW (0 processed) in 0.76s]
08:13:30  10 of 21 START sql table model YOUR_DATASET.stg_nodes ................... [RUN]
08:13:34  10 of 21 OK created sql table model YOUR_DATASET.stg_nodes .............. [CREATE TABLE (0.0 rows, 0 processed) in 4.75s]
08:13:34  11 of 21 START sql table model YOUR_DATASET.stg_sources ................. [RUN]
08:13:37  11 of 21 OK created sql table model YOUR_DATASET.stg_sources ............ [CREATE TABLE (0.0 rows, 0 processed) in 2.42s]
08:13:37  12 of 21 START seed file YOUR_DATASET.dbt_project_evaluator_exceptions .. [RUN]
08:13:40  12 of 21 OK loaded seed file YOUR_DATASET.dbt_project_evaluator_exceptions  [INSERT 0 in 2.79s]
08:13:40  13 of 21 START sql view model YOUR_DATASET.stg_exposure_relationships ... [RUN]
08:13:40  13 of 21 OK created sql view model YOUR_DATASET.stg_exposure_relationships  [CREATE VIEW (0 processed) in 0.56s]
08:13:40  14 of 21 START sql view model YOUR_DATASET.stg_metric_relationships ..... [RUN]
08:13:41  14 of 21 OK created sql view model YOUR_DATASET.stg_metric_relationships  [CREATE VIEW (0 processed) in 1.05s]
08:13:41  15 of 21 START sql table model YOUR_DATASET.stg_node_relationships ...... [RUN]
08:13:43  15 of 21 OK created sql table model YOUR_DATASET.stg_node_relationships . [CREATE TABLE (38.0 rows, 3.4 KiB processed) in 2.21s]
08:13:43  16 of 21 START sql view model YOUR_DATASET.stg_columns .................. [RUN]
08:13:44  16 of 21 OK created sql view model YOUR_DATASET.stg_columns ............. [CREATE VIEW (0 processed) in 0.86s]
08:13:44  17 of 21 START sql table model YOUR_DATASET.int_all_graph_resources ..... [RUN]
08:13:48  17 of 21 OK created sql table model YOUR_DATASET.int_all_graph_resources  [CREATE TABLE (6.0 rows, 10.3 KiB processed) in 3.68s]
08:13:48  18 of 21 START sql table model YOUR_DATASET.fct_hard_coded_references ... [RUN]
08:13:50  18 of 21 OK created sql table model YOUR_DATASET.fct_hard_coded_references  [CREATE TABLE (1.0 rows, 283.0 Bytes processed) in 2.42s]
08:13:50  19 of 21 START sql table model YOUR_DATASET.int_direct_relationships .... [RUN]
08:13:53  19 of 21 OK created sql table model YOUR_DATASET.int_direct_relationships  [CREATE TABLE (6.0 rows, 4.4 KiB processed) in 3.02s]
08:13:53  20 of 21 START test is_empty_fct_hard_coded_references_ ........................ [RUN]
08:13:54  20 of 21 WARN 1 is_empty_fct_hard_coded_references_ ............................ [WARN 1 in 0.91s]
08:13:54  21 of 21 START sql table model YOUR_DATASET.int_all_dag_relationships ... [RUN]
08:13:58  21 of 21 OK created sql table model YOUR_DATASET.int_all_dag_relationships  [CREATE TABLE (3.0 rows, 2.0 KiB processed) in 3.33s]
08:13:58  
08:13:58  Finished running 1 seed, 14 table models, 1 test, 5 view models in 0 hours 0 minutes and 49.82 seconds (49.82s).
08:13:58  
08:13:58  Completed with 1 warning:
08:13:58  
08:13:58  Warning in test is_empty_fct_hard_coded_references_ (models/marts/dag/dag.yml)
08:13:58  Got 1 result, configured to warn if != 0
08:13:58  
08:13:58    compiled code at target/compiled/dbt_project_evaluator/models/marts/dag/dag.yml/is_empty_fct_hard_coded_references_.sql
08:13:58  
08:13:58  Done. PASS=20 WARN=1 ERROR=0 SKIP=0 NO-OP=0 TOTAL=21

ログの最後の方を見てみると、 is_empty_fct_hard_coded_references_ という dbt テストで結果が 0 件でなかったために warning が出ていることが確認できる。

08:13:58  Completed with 1 warning:
08:13:58  
08:13:58  Warning in test is_empty_fct_hard_coded_references_ (models/marts/dag/dag.yml)
08:13:58  Got 1 result, configured to warn if != 0
08:13:58  
08:13:58    compiled code at target/compiled/dbt_project_evaluator/models/marts/dag/dag.yml/is_empty_fct_hard_coded_references_.sql

compiled code である is_empty_fct_hard_coded_references_.sql を見てみると、次のような SQL が記載されている。

is_empty_fct_hard_coded_references_.sql
    select count(*) as n_records
    from `YOUR_GC_PROJECT`.`YOUR_DATASET`.`fct_hard_coded_references`

fct_hard_coded_references テーブルの中身を確認してみると、次の1件のレコードが入っていた。

model               hard_coded_references
-----               ---------------------
my_second_dbt_model `YOUR_GC_PROJECT.YOUR_DATASET.my_first_dbt_model`

このレコードから my_second_dbt_modelYOUR_GC_PROJECT.YOUR_DATASET.my_first_dbt_modelref() を使わずに直接参照していることがわかる。

GitHub Actions での実行

dbt_project_evaluator は dbt テストがこけた時の重要度をデフォルトだと「 warning 」に設定している。GitHub Actions 等で実行する場合、 「 error 」にしないと運用しづらい。

その場合、次のように設定することで重要度を変更できる。

dbt_project.yml
data_tests:
  dbt_project_evaluator:
    +severity: "{{ env_var('DBT_PROJECT_EVALUATOR_SEVERITY', 'error') }}"

参考: Run in CI Check - dbt_project_evaluator

これにより、次のような感じで GitHub Actions ワークフローのステップを組んであげれば、 dbt_project_evaluator で引っかかった時に CI を落とすことができる。

.github/workflows/YOUR_GHA_WORKFLOW.yml
jobs:
  YOUR_JOB_NAME:
    runs-on: ubuntu-latest
    
    steps:

      - 〜〜(中略)〜〜
    
      - name: Build dbt_project_evaluator models
        id: evaluator_tests
        run: dbt build --select package:dbt_project_evaluator

      - name: Fail if evaluator tests failed
        if: steps.evaluator_tests.outcome == 'failure'
        run: exit 1

運用時の留意点

普通に dbt run すると models/ 配下の dbt モデルに加えて dbt_project_evaluator の dbt モデルも生成される。

多くの dbt プロジェクトでは本番環境と開発環境を分けて運用していると思う。本番環境において dbt_project_evaluator のモデルは基本的に不要だと思うので、生成されないようにしたくなると思う。

この対応として、主に以下の2つのアプローチが考えられる。

1. 実行コマンドで制御する

手っ取り早いのは dbt run --select models/*models/ 配下の dbt モデルのみを対象とするよう指定する方法。

2. dbt_project.yml で制御する

dbt_project.yml でパッケージ側の enabled 設定を target.name によって切り替えることでも対応できる。

dbt_project.yml
models:
  dbt_project_evaluator:
    +enabled: "{{ target.name != 'prod' }}" # prod環境では無効にしておく

    marts:
      dag:
        +enabled: false
        fct_hard_coded_references:
          +enabled: "{{ target.name != 'prod' }}"
      documentation:
        +enabled: false
      governance:
        +enabled: false
      performance:
        +enabled: false
      structure:
        +enabled: false
      tests:
        +enabled: false

ただ、有効にしたいルールに都度 "{{ target.name != 'prod' }}" を書かないといけないので、あまり良い方法ではない気がしている…。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?