dbtでデータモデルを実体化:Materializations

こんにちは、六本木アナリティクスエンジニアのTaku(@aelabdata )です。

dbt入門の第9回です。前回は、データ分析の最終的な出口となる「Marts」レイヤーの設計について解説しました。Martsレイヤーは、分析のための「何(What)」を作るかという設計図でした。

今回のMaterialization(マテリアライゼーション)は、その設計図をデータウェアハウス上に「どのように(How)」効率良く構築するかという、いわば施工方法にあたります。

この概念は、dbtプロジェクト全体のパフォーマンスと効率を大きく左右する、非常に重要な鍵となります。一見すると少し技術的に聞こえるかもしれませんが、心配はいりません。この記事を読み終える頃には、Materializationを自信を持って使いこなし、より洗練されたデータパイプラインを構築するための第一歩を踏み出せているはずです。

この記事では、以下の内容を学びます。

  • Materializationとは何か?: dbt runの裏側で何が起きているのかを理解します。
  • 主な種類: viewtableという、最も基本的な2つのMaterializationの違いと特性を学びます。
  • ベストプラクティス: いつ、どちらのタイプを使うべきか、というシンプルな指針を学びます。
  • 設定方法: プロジェクト全体とモデル単位でMaterializationを簡単に設定する方法を学びます。

それでは、「Materializationsとは何か?」から見ていきましょう。

Materializationsとは何か?

dbt runというコマンドを一つ実行するだけで、私たちの書いたselect文がデータウェアハウス上で実体を持つオブジェクトに変換されます。

この魔法のようなプロセスの裏側で、一体何が起きているのでしょうか?

その答えこそが「Materialization」です。Materializationとは、dbtがモデル(あなたの書いたselect文)をデータウェアハウス内にどのように物理的に「実体化」させるかを定義する設定のことです。

dbtが裏側で何をしているか

通常、データウェアハウスでビューやテーブルを作成するには、CREATE VIEW AS ...CREATE TABLE AS ...といったDDL(データ定義言語)を直接記述する必要があります。しかし、dbtではMaterializationがこの複雑なDDLを抽象化してくれます。

私たちは、モデルを「ビューとして作る」のか「テーブルとして作る」のかを宣言するだけでよく、dbtがその宣言とデータウェアハウスの特性に応じて、最適なDDLを自動的に生成・実行してくれるのです。この宣言的なアプローチにより、私たちはプラットフォームごとの細かなSQL構文の違いを気にする必要がなくなり、最も重要な分析ロジックそのものに集中できるという大きなメリットが生まれます。

主なMaterializationの種類

dbtにはいくつかのMaterializationがありますが、初学者が最初にマスターすべきはviewtableの2つです。この2つの特性を理解することが、効率的なdbtプロジェクトを設計する上で非常に重要になります。

特性viewtable
データの実体 (Data Storage)クエリ定義のみを保存(データは持たない)データを物理的に保存する
クエリ実行速度 (Query Speed)遅い傾向(実行時に都度クエリを計算)速い傾向(計算済みの物理データを参照)
ビルド(dbt run)速度 (Build Speed)速い(定義の作成のみ)遅い傾向(実データへの書き込みが発生)
データの鮮度 (Data Freshness)常に最新(参照元のデータが更新されれば追随)最後のdbt run時点のデータ
高度なオプション

tableのビルドに非常に時間がかかるようになった場合、incrementalというMaterializationが役立ちます。これは、モデル全体を再構築するのではなく、unique_key(例:customer_id)などを基に、新しく追加・変更されたデータのみをテーブルに効率的に追記する高度な方法です。まずはviewtableを使いこなし、次のステップとしてincrementalの学習に進むと良いでしょう。

ベストプラクティス:いつどれを使うべきか

では、viewtableをどのように使い分ければよいのでしょうか?dbt Labsが提唱する指針は、驚くほどシンプルです。

Guiding Principle

  1. まずはviewから始める。
  2. viewのクエリがエンドユーザー(BIツールなど)にとって遅くなったら、tableに変更する。
  3. tableのビルド(dbt run)に時間がかかりすぎるようになったら、incrementalを検討する。

この原則は、dbtプロジェクトのレイヤー構造とも密接に関連しています。

  • Stagingレイヤー: ソースデータを軽く整形するだけのモデルが多いため、ビルドが速く、常に最新データを参照できるviewが適しています。
  • Martsレイヤー: BIツールからのクエリや、複数のデータソースを結合した複雑な集計が含まれることが多いため、クエリパフォーマンスを優先してtableが適しています。

このシンプルな指針に従うだけで、プロジェクトのパフォーマンスと運用コストのバランスを適切に保つことができます。

それでは、実際にこれらのMaterializationをどのように設定するのか、次のセクションで見ていきましょう。

Materializationsの設定方法

dbtの素晴らしい点の一つは、設定の柔軟性です。プロジェクト全体で一貫したルールを適用しつつ、特定のモデルに対しては個別の要件に合わせて例外を設けることが簡単にできます。Materializationの設定も、この原則に従って2つの主要な方法で行います。

プロジェクト全体/ディレクトリ単位での設定 (dbt_project.yml)

プロジェクトの基本的な振る舞いを定義するのがdbt_project.ymlファイルです。ここで、プロジェクト全体、あるいは特定のディレクトリ配下のモデルに対するデフォルトのMaterializationを設定できます。

例えば、私たちのjaffle_shop_tutorialプロジェクトでは、「デフォルトはすべてviewとして作成し、BIツールから参照されるmartsディレクトリ配下のモデルだけはパフォーマンスのためにtableとして作成する」というルールを適用したいとします。その場合、dbt_project.ymlに以下のように記述します。

dbt_project.yml
models:
  jaffle_shop_tutorial:
    # このプロジェクト配下のモデルは、デフォルトでviewとして作成される
    +materialized: view
    
    # ただし、martsディレクトリ配下のモデルはtableとして作成する
    marts:
      +materialized: table

+記号は、この設定がサブディレクトリにも適用されることを意味します。この設定により、開発者は個々のモデルでMaterializationを意識することなく、プロジェクト全体で一貫したルールを維持できます。

モデル単位での設定 (configブロック)

プロジェクト全体のルールに対して、特定のモデルだけ異なる振る舞いをさせたい場合があります。そんな時に役立つのが、SQLファイル内に直接記述するconfigブロックです。

例えば、プロジェクト全体ではviewをデフォルトにしていても、特定のモデルだけパフォーマンス上の理由でtableとして作りたい場合があります。その際、このようにconfigブロックでmaterialized = 'table'と指定するだけで、dbt_project.ymlの設定を上書きできます。

今回は使用しませんが、例を示します。

{{
  config(
    materialized = 'table'
  )
}}

select * from {{ source('jaffle_shop', 'raw_customers') }}

このconfigブロックは、dbt_project.ymlで設定した全体ルールに対する「例外」を指定する際に非常に便利です。この仕組みにより、「全体ルール」と「個別例外」を柔軟に組み合わせることができ、メンテナンス性の高いプロジェクトを維持することが可能になります。

まとめと次のステップ

この記事では、dbtの強力な機能であるMaterializationについて、その基本から実践的な設定方法までを解説しました。

dbt runの裏側で何が起きているのかを理解し、viewtableのシンプルな使い分け、そしてdbt_project.ymlconfigブロックによる2つの設定方法をマスターすることは、あなたが効率的でスケーラブルなデータパイプラインを構築する上で、非常に大きな一歩となります。

今回学んだ重要なポイントを振り返りましょう。

  • Materialization: モデルをviewで作るかtableで作るかをdbtに指示する設定。
  • ベストプラクティス: 「まずviewで作り、パフォーマンスが必要になったらtableにする」というシンプルな指針。
  • 設定方法: dbt_project.ymlで全体的に、個別のモデルではconfigブロックで例外を指定。

Materializationを使いこなすことで、モデルの物理的な形を自在に操れるようになりました。しかし、作成したモデルのデータが本当に信頼できるものであるかは、また別の問題です。

次回は作成したモデルの品質を保証するための仕組み、dbt testについて掘り下げていきます。データモデルの「形」だけでなく、その「中身」の品質も担保することで、真に信頼されるデータ基盤を構築していきましょう。ご期待ください!