🍊

Jupyter Notebook 上で dbt を使いたい

に公開

はじめに

現在の開発環境では、VSCode 上で dbt Core を使ってモデリングを行っています。しかし、基本的にクエリを実行するたびに前回の結果が上書きされてしまうため、「データを継続的に見ながら開発するのが少し不便だな」と感じていました。

もともと私はデータアナリストとしてのバックグラウンドがあり、探索的なデータ分析には Jupyter Notebook をよく活用していました。そこで、「もし Jupyter Notebook 上で dbt のモデリングができれば、もっと快適に開発できるのではないか?」と思いました。

自分の悩みは世界の誰かが同じ悩みを持っていると思って調べましたが、使えるライブラリはありませんでした。
↓それっぽい感じでしたが、自分の環境では動きませんでした。
https://github.com/butchland/nbdbt
https://github.com/jmriego/dbt-ipy

なので、自分で作りました( ´∀`)

前提条件

  • VSCode 上で dbt Core を使った開発環境がある
  • VSCode 上で Jupyter Notebook を利用できる

dbt-magicsとは?

https://github.com/1210yuichi0/dbt-magics

dbt-magics は、Jupyter Notebook で dbt を操作するためのカスタムマジックコマンドです。

これにより、以下のようなことが可能になります

  • %%dbt_show を使って dbtのクエリをそのまま実行
  • クエリ結果を Pandas DataFrame として取得・変数に格納
  • %%dbt_compile で SQL を dbt のコンテキストでコンパイル

インストール方法

  1. dbt-magics をインストールします
pip install git+https://github.com/1210yuichi0/dbt-magics.git
  1. Jupyter Notebook 上でマジックコマンドを読み込みます
%load_ext dbt_magics

使い方とユースケース

データのプレビュー

%%dbt_show
SELECT * FROM {{ ref('sales_data') }}

Jupyter Notebook 上に直接テーブルが表示されるので、確認が非常にスムーズです。

データを変数に保存して加工

クエリの結果を DataFrame に保存して、Python で加工することも可能

%%dbt_show customer_df
SELECT * FROM {{ ref('customer_data') }}

その後は普通に customer_df.head() のように使えます。

SQLのコンパイルだけ行いたい場合

%%dbt_compile
SELECT * FROM {{ ref('inventory') }}

dbt compile の出力をその場で確認できます。エラーの早期発見に便利です。

結果をクリップボードにコピーする

以下のように %%dbt_show copydf を使うことで、クエリ結果を クリップボードにコピー することができます

%%dbt_show copydf
SELECT * FROM {{ ref('customer_data') }}

これにより、実行結果をそのまま Excel やスプレッドシートなどに貼り付けて共有するのが簡単になります。

よく使っている dbt macro

Jupyter Notebook 上で dbt を使用する際に合わせてよく利用している dbt macro を紹介します
※ BigQuery を前提にしています。

dbt モデルのカラム情報を取得する

これから利用するdbt モデルのパーティションやクラスタのカラムを確認するために使っている

実行サンプル1
{{ get_table_columns(source("jaffle_shop", "customers")) }}
実行サンプル2
{{ get_table_columns(ref("stg_customers")) }}
dbt_project/macros/utils/get_table_columns.sql
{% macro get_table_columns(model) %}
    select
        c.ordinal_position as column_no,
        c.column_name,
        d.description,
        c.data_type,
        c.is_partitioning_column as partition_by,
        c.clustering_ordinal_position as cluster_by
            from `{{ model.schema }}`.INFORMATION_SCHEMA.COLUMNS as c -- fmt: off
            left join
                `{{ model.schema }}`.INFORMATION_SCHEMA.COLUMN_FIELD_PATHS  as d -- fmt: on
        on c.column_name = d.column_name
        and c.table_name = d.table_name
    where c.table_name = '{{ model.identifier }}'
    order by c.ordinal_position
{% endmacro %}

dbt モデルのカラムサンプル取得する

これから利用するdbt モデルのカラムサンプルを確認するために使っている
dbt_utilsのパッケージが必要。
結構乱暴なクエリなので、コストと相談して実行ください。

実行サンプル1
{{ get_column_samples(source("jaffle_shop", "customers")) }}
実行サンプル2
{{ get_column_samples(ref("stg_customers")) }}
dbt_project/macros/utils/get_table_columns.sql
{% macro get_column_samples(model, sample_size=10) %}

{% set columns = dbt_utils.get_filtered_columns_in_relation(from=model) %}

with
    column_info as (
        select
            c.ordinal_position as column_no, c.column_name, d.description, c.data_type,
        from `{{ model.schema }}`.INFORMATION_SCHEMA.COLUMNS c -- fmt: off
        left join
            `{{ model.schema }}`.INFORMATION_SCHEMA.COLUMN_FIELD_PATHS d -- fmt: on
            on c.column_name = d.column_name
            and c.table_name = d.table_name
        where c.table_name = '{{ model.identifier }}'
    ),
    sample_values as (
        {% for col in columns %}
            select '{{ col }}' as column_name, cast({{ col }} as string) as value
            from (select {{ col }} from {{ model }} where {{ col }} is not null limit {{ sample_size }})
            {% if not loop.last %}
                union all
            {% endif %}
        {% endfor %}
    )
select
    ci.column_no,
    ci.column_name,
    ci.description,
    ci.data_type,
    string_agg(distinct sv.value, " | ") as samples
from column_info ci
left join sample_values sv on ci.column_name = sv.column_name
group by ci.column_no, ci.column_name, ci.description, ci.data_type
order by ci.column_no asc

{% endmacro %}

おわりに

dbt-magics を使えば、Jupyter Notebook 上で dbt の開発やデバッグがとても快適になります。特に「素早くデータを確認したい」「クエリの動作を試したい」といったシーンで効果を発揮するでしょう。

普段の dbt 開発に Jupyter Notebook を取り入れることで、より柔軟で効率的なワークフローを実現してみてください。

※ 初めて作った Python パッケージなので、優しいフィードバックをお待ちしています!

参考

https://github.com/butchland/nbdbt
https://github.com/jmriego/dbt-ipy
https://dk521123.hatenablog.com/entry/2024/07/20/034930
https://docs.getdbt.com/reference/commands/show
https://qiita.com/konbraphat51/items/4602ebcfcdb6e03c16bd
https://ipython.readthedocs.io/en/8.17.1/config/custommagics.html
https://zenn.dev/karaage0703/articles/db8c663640c68b
https://zenn.dev/ds_rd/articles/pandas_clipboard
https://stackoverflow.com/questions/46547299/jupyter-server-dfdata-to-clipboard-from-remote-to-local-machine-how
https://nikkie-ftnext.hatenablog.com/entry/why-dont-you-write-pyproject-toml-instead-of-setup-py
https://packaging.python.org/ja/latest/tutorials/packaging-projects/

Discussion