Snowflake & dbt Cloudハンズオン実践 #7: 『実践編4(テスト&ドキュメント)』 #snowflakeDB #dbt

2024.01.31

アライアンス事業部 エンジニアグループ モダンデータスタック(MDS)チームの しんや です。

Snowflakeが展開しているサイト『Snowflake Quickstarts』では、Snowflake単体、またSnowflakeと他サービスとの連携について実戦形式で手を動かしながら学んでいけるコンテンツが多数公開されています。

その中の1つ『Accelerating Data Teams with Snowflake and dbt Cloud Hands On Lab(Snowflake と dbt Cloud ハンズオン ラボを使用してデータ チームを加速する)』は、dbt CloudとSnowflakeを連携させる形で、Snowflakeのデータを使ってdbt Cloudでデータ変換の処理を作り上げていく流れを学ぶことが出来る非常に参考になるコンテンツです。

当エントリ及び一連のエントリ群では、この一連の手順を実際に手を動かしながら進めた記録をまとめて行こうと思います。

第7弾の当エントリでは『実践編4(テスト&ドキュメント)』パートについて実践内容を紹介します。

一連の内容を1本にまとめようとするとめちゃくちゃボリュームが大きくなる内容でしたので、以下の形でそれぞれ分けて紹介していこうと思います。
#1: Snowflake環境準備編 [Snowflake QuickStarts: Step01-04]
#2: dbt Cloud IDE探索編 [Snowflake QuickStarts: Step05]
#3: dbt Cloud 基本構造紹介編 [Snowflake QuickStarts: Step06]
#4: dbt Cloud 実践編1(ソース設定&ステージングモデル作成) [Snowflake QuickStarts: Step07]
#5: dbt Cloud 実践編2(シード&マテリアライゼーション) [Snowflake QuickStarts: Step08]
#6: dbt Cloud 実践編3(マートモデルの作成) [Snowflake QuickStarts: Step09]
#7: dbt Cloud 実践編4(テスト&ドキュメント) [Snowflake QuickStarts: Step10]
#8: dbt Cloud 実践編5(デプロイ) [Snowflake QuickStarts: Step11]
#9: Snowsightダッシュボード可視化編 [Snowflake QuickStarts: Step12]

目次

 

Step10. テストとドキュメント

モデルや変換を構築した後は、それを文書化しテストすることが非常に重要です。dbtのネイティブ機能には、データテストとドキュメンテーションのフレームワークが含まれており、ドキュメンテーションとテストのニーズをすべて満たすことができます。

 

テストについて

dbtにおけるテストには汎用テストと単数テストの2種類があります。 - 単一テスト(Singular Test):最も単純な形のテスト。失敗した行を返すSQLクエリを書くことができれば、それはdbt testコマンドで実行できるdbtテストとなる - 汎用テスト(Generic Test):引数を受け取ることができるテスト。。テストブロック(マクロに似ています)の中で定義し、.ymlファイルの中で名前を付けて参照することができる(モデル、カラム、ソース、スナップショット、シードに適用)。 - 以下4つのテストが同梱されている - unique - not null - accepted values - relationships

また、dbtのカスタムテストの一端を理解するために、独自の単数テストを書いてみます。ちなみにdbt_utilsパッケージやdbt_expectationsのようなパッケージから他の汎用テストにアクセスすることもできます。

 

ドキュメントについて

dbtは、他のデータチームメンバーや利害関係者が利用できるように、Snowflake情報スキーマの詳細だけでなく、あなたが提供できるカラムとモデルレベルの説明の両方を静的サイトにまとめます。

 

テスト(Tests)と説明(descriptions)を作成

『一般的なテスト』と『ドキュメントの説明』はどちらもYAMLファイルで定義されます。

まず最初に、core.ymlというファイルをファイルパス:models/marts/core/core.ymlで作成します。

このファイルの解説ポイントは以下の通り。

  • ファイルはmodels/marts/core/配下にあり、このディレクトリにあるモデル(この場合はfct_orders)専用のテストと説明が含まれている
    • YAMLファイルとテストし定義するモデルをどのように整理したいかはあなたとあなたのチーム次第
    • ベストプラクティスとして、1つのディレクトリに少なくとも1つのテストとドキュメント用のYAMLファイルを持つことを推奨
  • 記載形式
    • トップレベルは記述しているモデルで、モデル名の下に直接モデルレベルの情報を記述
    • また、モデルの説明(description)を記述しており、このモデルのドキュメントサイトを表示すると、これがモデルレベルとして表示される
  • カラムレベルの指定
    • 記述とテストの両方の観点から、ほとんどの作業がここで行われている
    • このモデルのテストは様々なカラムですべての一般的なテストを利用していることがわかる
      • 例).order_keyが一意であり、かつnot_nullであることを期待し、関連するテストを使ってチェックしている
  • 関連性テスト
    • このモデルのorder_keyがstg_tpch_ordersのidとしても存在することを確認している
  • accepted valuesテスト
    • status_codeカラムから出力される値が期待値に合うことを確認するために、accepted valuesテストがある
  • 説明(description)
    • 2つの異なる表記に分かれている
      • 1つはプレーンテキストを使い、もう1つはdocブロックへのjinja参照を使っている
    • プレーンテキストの説明はモデルレベルと同じように動作し、YAML ファイルの任意のカラムをドキュメント化できる
    • docブロックは次のステップで説明するmarkdownファイルに記述することを可能にすることで、ドキュメントの機能を拡張

models/marts/core/core.yml

version: 2

models:
  - name: fct_orders
    description: orders fact table
    columns:
      - name: order_key
        description: primary key of the model
        tests:
          - unique
          - not_null
          - relationships:
              to: ref('stg_tpch_orders')
              field: order_key
              severity: warn
      - name: customer_key
        description: foreign key for customers
      - name: order_date
        description: date of the order
      - name: status_code
        description: status of the order
        tests:
          - accepted_values:
              values: ['P','O','F']
      - name: priority_code
        description: code associated with the order
      - name: clerk_name
        description: id of the clerk
      - name: ship_priority
        description: numeric representation of the shipping priority, zero being the default
      - name: order_count
        description: count of order
      - name: gross_item_sales_amount
        description: '{{ doc("gross_item_sales_amount") }}'
      - name: item_discount_amount
        description: item level discount amount. this is always less than or equal to zero
      - name: item_tax_amount
        description: item level tax total
      - name: net_item_sales_amount
        description: the net total which factors in discount and tax

 

マークダウンファイルのビルド

dbtのドキュメントでは、docブロックの説明に付随するマークダウン・ファイルを作って設定することが出来ます。次のファイルパスでcore.mdという新しいファイルを作成します: models/marts/core/core.md

models/marts/core/core.md

# the below are descriptions from fct_orders

{% docs gross_item_sales_amount %} same as extended_price {% enddocs %}

このマークダウンファイルはYAMLファイルのdocブロックの説明を持つ1つのカラムに対応する1つのdocブロックを持ちます(マークダウンファイルは複数のdocブロックを持つことができることに注意)。

YAMLのdocブロックの説明の引用符で囲まれた名前はマークダウンファイルの冒頭のdocブロックの名前に接続します。この場合、YAML記述の'{{doc("gross_item_sales_amount") }}'はマークダウンファイルの{% docs gross_item_sales_amount %}にマッチします。この流れでマークダウンファイルのテキストの説明がYAMLファイルの説明として渡され、ドキュメントサイトで対応するモデルを開いたとき、この内容が表示されます。

マークダウンファイルでdocブロックを使って説明文を構築することで、マークダウンで説明文をフォーマットすることができ、カラムやモデルレベルで長い説明文を構築するときに特に役立ちます。また、同じ説明を持つカラムが複数のモデルに存在する場合、そのカラムに対して同じdocブロックを何度でも再利用することができます。docブロックについての詳細は下記ドキュメントをご参照ください。

 

単一テストのビルド

データベースの説明を見てみると、項目:item_discount_amountはそのカラムの出力が常に0以下であることを指定していることがわかります。であればそれをテストしましょう。この場合、カスタムデータテストを作成する必要があります。

test/フォルダにfct_orders_negative_discount_amount.sqlというファイルを作成。

test/fct_orders_negative_discount_amount.sql

--If no discount is given it should be equal to zero 
--Otherwise it will be negative

select *
  from {{ ref('fct_orders') }}  
 where item_discount_amount > 0

カスタムテストはSQLのselect文として記述され、テストに失敗すると失敗したレコードが出力として返されます。つまり、テストに合格するためには、結果は行を返さないことになり、このことを想定してテストを書く必要があります。item_discount_amountが常に0以下であるという前提で、item_discount_amountが0より大きいかどうかをテストします。select文のwhere句はこのために書かれ、失敗したレコードがあればそれを返します。

このテストをYAMLファイルに記述していない場合、dbtはどうやってこのテストを実行するタイミングを知るのでしょうか?それは、(dbt_project.ymlファイルで定義された)testsディレクトリにあるファイルと、適切なモデルとの依存関係を作成するためにref関数を使うselect文の組み合わせです。こうすることで、dbt testコマンドを使用してそのモデルをテストするときはいつでも、このテストは他のすべてのカラムレベルのテストと一緒に実行されます。

 

テストの実行

作成したテストの実行をしてみます。以下のコマンドをdbt Cloud IDEで実行。dbt test --select fct_orders

モデルの実行と同時にそれぞれのテストが実行されます。

 

ドキュメントの作成と内容の確認

ドキュメントの作成はコマンド:dbt docs generateで実行可能です。

このコマンドを実行し、完了したらIDEの左上、バージョン管理ペインの上にあるブックアイコンをクリックしてドキュメントを起動してください。

ドキュメントサイトが新しいタブで起動します。読み込み後、一番上の検索バーにfct_ordersと入力し、一番上の結果をクリックすると、そのモデルのドキュメントが表示されます。

読み込みが完了したら、モデルレベルの説明、YAML ファイルに記述したカラムレベルの説明、doc ブロックの説明を見ることができます。また、テストを持つ2つのカラムに対して実行されるテストへの参照を見ることができます。

更に展開していくと、このモデルと他のモデルとの関係に関する情報も見ることも出来ます。

右下のバブルをクリックすると血統グラフのプレビューが表示され、右上の拡大ボタンをクリックすると全景が表示されます。

プロジェクト全体でref関数を使用してモデルを参照することで、dbtが依存関係や系統を構築できるようになるという最終的な結果が上記の内容となります。

リネージグラフは強力な機能で、プロジェクトが大きくなるにつれてさらに強力になり、プロジェクトが成長し続けるにつれて、より多くの情報に基づいたアーキテクチャの議論ができるようになります。

 

まとめ

という訳で、Snowflake QuickStarts『Accelerating Data Teams with Snowflake and dbt Cloud Hands On Lab』実践第7弾、dbt Cloud実践編4(テスト&ドキュメント)に関する内容の紹介でした。

次エントリ(第8弾)ではdbt Cloudでのモデル作成実践編その5(デプロイ)に関するパートを進めていきます。