dbtのベストプラクティスをより理解するために、dbt-athenaを使って新規プロジェクトからdbtのベストプラクティスに寄せてみた

2023.11.06

こんちには。

データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。

今回は、dbtのベストプラクティスをより理解するために、dbt-athenaを使って新規プロジェクトからdbtのベストプラクティスに寄せてみたいと思います。

ベストプラクティスについて

ベストプラクティスの記載

ベストプラクティスの情報源としては以下を参考にします。

また、これらを別途まとめてくださっている方の記事も以下にあります。

ベストプラクティスの私的まとめ

まとめ記事と重複してしまいますが、私が理解したベストプラクティスをまとめます。

ポイントを以下に列挙します。

  • models配下は以下の3層構造
    • staging、intermediate、marts
  • stagingレイヤ
    • 命名規則 : stg_{source_name}__{table_name}.sql
    • {source_name}毎にサブフォルダに分割
    • この層でやること : リネーム、キャスト、単位変換、カテゴリ変数のエンコード
    • この層でやらないこと : join、aggregate(例外あり)
    • materialized設定はview
    • stagingレイヤはsourceを入力として使用する唯一の場所
    • stagingレイヤのモデルはソーステーブルと1対1対応
    • intermediate、martsはこのstagingレイヤのモデルを参照(ref)
  • intermediateレイヤ
    • 命名規則 : int_[entity]s_[verb]s.sql
    • materialized設定はephemerally(WITH句)
    • 厳密な名づけルールは困難だが、intermediateレイヤの動詞で考えるのが良い指針(pivoted、joinedなど)
    • intermediateレイヤはエンドユーザ(ダッシュボードやアプリなど)に非公開
    • intermediateレイヤの目的はmartsレイヤの複雑さの解消
    • そのため早い段階では不使用を推奨(martsレイヤのモデルが10個未満など)
    • サブディレクトリも早い段階では不使用を推奨
  • martsレイヤ
    • 命名規則 : ルールは存在せず、実際に示すテーブル名通り
    • materialized設定はtableまたはincremental
    • intermediateレイヤ同様、早い段階ではサブフォルダ分割等は不使用を推奨
  • ymlファイル
    • schema.yml一つに書くのではなくmodelsとsourcesに分割するのが良い
    • 命名規則 : _[directory]__models.yml_[directory]__sources.yml
  • doc(markdown)ファイル
  • materializedなどの設定
    • 通常はdbt_project.ymlなどに各フォルダで共通の設定を記載することを推奨
  • selectはタグ指定よりもフォルダ指定の方がベター
    • dbt run --select tag:marketingよりもdbt run --select marts.marketing
    • タグ指定は仕様の暗黙的な理解が必要で、フォルダ指定よりもタグの付け忘れが多くなることが理由

フォルダ・ファイル構成例

これらのベストプラクティスに基づくフォルダ・ファイルの構成例として示されているのが以下です。

jaffle_shop
├── README.md
├── analyses
├── seeds
│   └── employees.csv
├── dbt_project.yml
├── macros
│   └── cents_to_dollars.sql
├── models
│   ├── intermediate
│   │   └── finance
│   │       ├── _int_finance__models.yml
│   │       └── int_payments_pivoted_to_orders.sql
│   ├── marts
│   │   ├── finance
│   │   │   ├── _finance__models.yml
│   │   │   ├── orders.sql
│   │   │   └── payments.sql
│   │   └── marketing
│   │       ├── _marketing__models.yml
│   │       └── customers.sql
│   ├── staging
│   │   ├── jaffle_shop
│   │   │   ├── _jaffle_shop__docs.md
│   │   │   ├── _jaffle_shop__models.yml
│   │   │   ├── _jaffle_shop__sources.yml
│   │   │   ├── base
│   │   │   │   ├── base_jaffle_shop__customers.sql
│   │   │   │   └── base_jaffle_shop__deleted_customers.sql
│   │   │   ├── stg_jaffle_shop__customers.sql
│   │   │   └── stg_jaffle_shop__orders.sql
│   │   └── stripe
│   │       ├── _stripe__models.yml
│   │       ├── _stripe__sources.yml
│   │       └── stg_stripe__payments.sql
│   └── utilities
│       └── all_dates.sql
├── packages.yml
├── snapshots
└── tests
    └── assert_positive_value_for_total_amount.sql

構成例に基づいたGitHubのPublic Template

実際この構成例通りのレポジトリは見つけられなかったのですが、dbt-labsが公開しているものの中では以下のPublic Templateが最も近いように見えました。

今回は、新規プロジェクトをdbt-athenaで作成し、こちらの例を参考にしながらベストプラクティスに近づけていく作業をやりたいと思います。

やってみた

dbt実行環境の準備

まずはdbtの実行環境を構築します。

pyenv + poetryでPython環境を構築している前提で記載します。ご自身の環境に合わせて適宜読み返されてください。

# Pythonバージョンの設定
pyenv local 3.11.5

# poetryの初期化
poetry init

# dbtのモジュールをインストール
poetry add "dbt-core>=1.6.0,<1.7.0" dbt-athena-community

# バージョン確認
poetry export | grep "dbt" | awk '{print $1}'

# dbt-athena-community==1.6.4
# dbt-core==1.6.7
# dbt-extractor==0.4.1
# dbt-semantic-interfaces==0.2.3

# poetry環境へ入る
poetry shell

# dbtコマンド側でもバージョン確認
dbt --version

# Core:
#   - installed: 1.6.7
#   - latest:    1.7.0 - Update available!
#
#   Your version of dbt-core is out of date!
#   You can find instructions for upgrading here:
#   https://docs.getdbt.com/docs/installation
#
# Plugins:
#   - athena: 1.6.4 - Ahead of latest version!

こちらで一通り実行環境の構築が可能です。

dbtプロジェクト作成

最初からdbt initで対話的にプロジェクトを作成しても良いのですが、結局のところ前回のブログでもお示した通りseed_s3_upload_argsの設定がうまくできないので、最初に~/.dbt/profiles.ymlに以下を記載しておきます。

jaffle_shop:
  outputs:
    dev:
      database: awsdatacatalog
      region_name: ap-northeast-1
      s3_data_dir: s3://{ご自身のバケット名}/dbt/athena_query_result
      s3_staging_dir: s3://{ご自身のバケット名}/dbt/tables
      schema: jaffle_shop
      seed_s3_upload_args: {}
      threads: 1
      type: athena
  target: dev

なお{ご自身のバケット名}の部分は適宜置き換えをお願いします。

ここでschema: jaffle_shopはデフォルトスキーマと呼ばれ、この名前が出力先のAthenaにおけるデフォルトのデータベース名となります。

データ自体もこのデフォルトスキーマに応じたS3のパスに保存され、今回の場合は以下がデフォルトの格納先となります。

  • s3://{ご自身のバケット名}/dbt/tables/jaffle_shop

そして以下のようにdbt initを実行するとprofiles.ymlを上書きしますか?とコンソールに聞かれるため、Noを選択してプロジェクトを作成します。

dbt init jaffle_shop

# 03:07:07  Running with dbt=1.6.7
# 03:07:07
# Your new dbt project "jaffle_shop" was created!
#
# For more information on how to configure the profiles.yml file,
# please consult the dbt documentation here:
#
#   https://docs.getdbt.com/docs/configure-your-profile
#
# One more thing:
#
# Need help? Don't hesitate to reach out to us via GitHub issues or on Slack:
#
#   https://community.getdbt.com/
#
# Happy modeling!
#
# 03:07:07  Setting up your profile.
# The profile jaffle_shop already exists in {profile.ymlのフルパス}. Continue and overwrite it? [y/N]: n

するとプロジェクトフォルダが作成されるため、その中に移動します。そこで接続設定の検証を行うためdbt debugを実行します。

(私は実際にはdbt debugaws-vault経由で行っています。ご自身の環境に応じてAWSプロファイルを有効にして実行されてください。)

# プロジェクトフォルダへ移動
cd ./jaffle_shop

# 接続設定の検証
dbt debug

# 03:00:20  Running with dbt=1.6.7
# 03:00:20  dbt version: 1.6.7
# 03:00:20  python version: 3.11.5
# 03:00:20  python path: {Pythonの実行ファイルのフルパス}
# 03:00:20  os info: Windows-10-10.0.19045-SP0
# 03:00:20  Using profiles dir at {profile.yml格納先フォルダ}
# 03:00:20  Using profiles.yml file at {profile.ymlのフルパス}
# 03:00:20  Using dbt_project.yml file at {dbt_project.ymlのフルパス}
# 03:00:20  adapter type: athena
# 03:00:20  adapter version: 1.6.4
# 03:00:20  Configuration:
# 03:00:20    profiles.yml file [OK found and valid]
# 03:00:20    dbt_project.yml file [OK found and valid]
# 03:00:20  Required dependencies:
# 03:00:20   - git [OK found]
#
# 03:00:20  Connection:
# 03:00:20    s3_staging_dir: s3://{ご自身のバケット名}/dbt/athena_query_result
# 03:00:20    work_group: None
# 03:00:20    region_name: ap-northeast-1
# 03:00:20    database: awsdatacatalog
# 03:00:20    schema: jaffle_shop
# 03:00:20    poll_interval: 1.0
# 03:00:20    aws_profile_name: None
# 03:00:20    aws_access_key_id: None
# 03:00:20    aws_secret_access_key: None
# 03:00:20    aws_session_token: None
# 03:00:20    endpoint_url: None
# 03:00:20    s3_data_dir: s3://{ご自身のバケット名}/dbt/tables
# 03:00:20    s3_data_naming: schema_table_unique
# 03:00:20    s3_tmp_table_dir: None
# 03:00:20    debug_query_state: False
# 03:00:20    seed_s3_upload_args: None
# 03:00:20    lf_tags_database: None
# 03:00:20  Registered adapter: athena=1.6.4
# 03:00:23    Connection test: [OK connection ok]
#
# 03:00:23  All checks passed!

上記のように問題ないことを確認できました。

以降はdbtプロジェクトフォルダ内で作業していきます。

dbt seedでソーステーブルを作成

dbt seedを使うことでcsvファイルからテーブルを作成することが可能です。

ファイルの追加

Public Templateの以下にcsvファイルが格納されています。

こちらから以下のファイルをseedsフォルダに配置します。

raw_customers.csv
raw_items.csv
raw_orders.csv
raw_products.csv
raw_stores.csv
raw_supplies.csv

dbt seedの実行

その後、dbt seedを実行します。

dbt seed

# 03:25:17  Running with dbt=1.6.7
# 03:25:17  Registered adapter: athena=1.6.4
# 03:25:17  Found 2 models, 6 seeds, 4 tests, 0 sources, 0 exposures, 0 metrics, 378 macros, 0 groups, 0 semantic models
# 03:25:17
# 03:25:22  Concurrency: 1 threads (target='dev')
# 03:25:22
# 03:25:22  1 of 6 START seed file jaffle_shop.raw_customers ............................... [RUN]
# 03:25:42  1 of 6 OK loaded seed file jaffle_shop.raw_customers ........................... [INSERT 939 in 19.32s]
# 03:25:42  2 of 6 START seed file jaffle_shop.raw_items ................................... [RUN]
# 03:26:03  2 of 6 OK loaded seed file jaffle_shop.raw_items ............................... [INSERT 95368 in 21.52s]
# 03:26:03  3 of 6 START seed file jaffle_shop.raw_orders .................................. [RUN]
# 03:26:32  3 of 6 OK loaded seed file jaffle_shop.raw_orders .............................. [INSERT 59652 in 28.66s]
# 03:26:32  4 of 6 START seed file jaffle_shop.raw_products ................................ [RUN]
# 03:26:50  4 of 6 OK loaded seed file jaffle_shop.raw_products ............................ [INSERT 10 in 17.91s]
# 03:26:50  5 of 6 START seed file jaffle_shop.raw_stores .................................. [RUN]
# 03:27:08  5 of 6 OK loaded seed file jaffle_shop.raw_stores .............................. [INSERT 5 in 18.19s]
# 03:27:08  6 of 6 START seed file jaffle_shop.raw_supplies ................................ [RUN]
# 03:27:27  6 of 6 OK loaded seed file jaffle_shop.raw_supplies ............................ [INSERT 65 in 18.83s]
# 03:27:27
# 03:27:27  Finished running 6 seeds in 0 hours 2 minutes and 9.38 seconds (129.38s).
# 03:27:27
# 03:27:27  Completed successfully
# 03:27:27
# 03:27:27  Done. PASS=6 WARN=0 ERROR=0 SKIP=0 TOTAL=6

profiles.ymlで設定したデフォルトスキーマ(データベース、S3パス)に、テーブルが作成されていることが分かります。

またGlueデータベースをあらかじめ作成していなくても、自動で作成されるため便利ですね。

カスタムスキーマを設定する

ソーステーブルをデフォルトスキーマに作成しましたが、通常ソーステーブルとdbtで作成するテーブルはデータベースを分けておきたいケースが考えられます。

それを考慮してか、Public Templateでは以下のようなmacros/generate_schema_name.sqlが追加されています。

{% macro generate_schema_name(custom_schema_name, node) %}

    {% set default_schema = target.schema %}

    {# seeds go in a global `raw` schema #}
    {% if node.resource_type == 'seed' %}
        {{ custom_schema_name | trim }}

    {# non-specified schemas go to the default target schema #}
    {% elif custom_schema_name is none %}
        {{ default_schema }}


    {# specified custom schema names go to the schema name prepended with the the default schema name in prod (as this is an example project we want the schemas clearly labeled) #}
    {% elif target.name == 'prod' %}
        {{ default_schema }}_{{ custom_schema_name | trim }}

    {# specified custom schemas go to the default target schema for non-prod targets #}
    {% else %}
        {{ default_schema }}
    {% endif %}

{% endmacro %}

こちらはカスタムスキーマを指定した際に実行されるマクロで、以下のようなロジックがマクロとして入っています。

  • node.resource_type == 'seed'で、seedの時はカスタムスキーマをそのままスキーマ名(データベース名)を使用
  • target.name == 'prod'で、targetがprodの時のみデフォルトスキーマとカスタムスキーマの連結がスキーマ名(データベース名)を使用

そのため、dbt_project.ymlに以下を追記してseedsのカスタムスキーマをjaffle_shop_rawに設定します。

seeds:
  jaffle_shop:
    +schema: jaffle_shop_raw

dbt seedの再実行

dbt seedの再実行をしますが、その前に一旦jaffle_shopというGlueデータベースを削除しておきます。

そして再度dbt seedを実行します。

dbt seed

# 01:36:03  Running with dbt=1.6.7
# 01:36:03  Registered adapter: athena=1.6.4
# 01:36:03  Found 6 seeds, 12 models, 6 sources, 0 exposures, 0 metrics, 624 macros, 0 groups, 0 semantic models
# 01:36:03
# 01:36:08  Concurrency: 1 threads (target='dev')
# 01:36:08
# 01:36:08  1 of 6 START seed file jaffle_shop_raw.raw_customers ........................... [RUN]
# 01:36:32  1 of 6 OK loaded seed file jaffle_shop_raw.raw_customers ....................... [INSERT 939 in 24.43s]
# 01:36:32  2 of 6 START seed file jaffle_shop_raw.raw_items ............................... [RUN]
# 01:36:59  2 of 6 OK loaded seed file jaffle_shop_raw.raw_items ........................... [INSERT 95368 in 26.71s]
# 01:36:59  3 of 6 START seed file jaffle_shop_raw.raw_orders .............................. [RUN]
# 01:37:36  3 of 6 OK loaded seed file jaffle_shop_raw.raw_orders .......................... [INSERT 59652 in 36.87s]
# 01:37:36  4 of 6 START seed file jaffle_shop_raw.raw_products ............................ [RUN]
# 01:38:00  4 of 6 OK loaded seed file jaffle_shop_raw.raw_products ........................ [INSERT 10 in 23.70s]
# 01:38:00  5 of 6 START seed file jaffle_shop_raw.raw_stores .............................. [RUN]
# 01:38:24  5 of 6 OK loaded seed file jaffle_shop_raw.raw_stores .......................... [INSERT 5 in 24.10s]
# 01:38:24  6 of 6 START seed file jaffle_shop_raw.raw_supplies ............................ [RUN]
# 01:38:48  6 of 6 OK loaded seed file jaffle_shop_raw.raw_supplies ........................ [INSERT 65 in 23.95s]
# 01:38:48
# 01:38:48  Finished running 6 seeds in 0 hours 2 minutes and 44.47 seconds (164.47s).
# 01:38:48
# 01:38:48  Completed successfully
# 01:38:48
# 01:38:48  Done. PASS=6 WARN=0 ERROR=0 SKIP=0 TOTAL=6

すると以下のようにスキーマ名(データベース名)がdbt_project.ymlに記述したjaffle_shop_rawへ変更することができました。

stagingレイヤのモデルの追加

ファイルの追加

Public Templateの以下にstagingレイヤのモデルのsqlファイルが格納されています。

こちらから以下のファイルをmodels/stagingフォルダに配置します。

__sources.yml
stg_customers.sql
stg_locations.sql
stg_order_items.sql
stg_orders.sql
stg_products.sql
stg_supplies.sql

sqlファイルはそのまま配置しますが、__sources.ymlは変更を加えます。

具体的にはfreshnessloaded_at_fieldに関する記述を削除した状態とします。これにより__sources.ymlは以下のようになります。

version: 2

sources:
  - name: ecom
    schema: jaffle_shop_raw
    description: E-commerce data for the Jaffle Shop
    tables:
      - name: raw_customers
        description: One record per person who has purchased one or more items
      - name: raw_orders
        description: One record per order (consisting of one or more order items)
      - name: raw_items
        description: Items included in an order
      - name: raw_stores
        description: Items included in an order
      - name: raw_products
        description: One record per SKU for items sold in stores
      - name: raw_supplies
        description: One record per supply per SKU of items sold in stores

stagingレイヤの命名規則について

ここではstagingフォルダ配下はサブフォルダ構成となっていないため、ベストプラクティスの命名規則 stg_{source_name}__{table_name}.sqlから{source_name}が省かれた状態となっています。

stagingするソースシステムが増えてきた場合は、サブフォルダ構成にする必要がありそうです。

materializedの設定

このstagingレイヤについてmaterializedを設定するため、dbt_project.ymlファイルに以下を追加します。

models:
  jaffle_shop:
    staging:
      +materialized: view

dbt runの実行でモデル作成

その後、dbt runでモデルを作成します。

dbt run

# 13:06:43  Running with dbt=1.6.7
# 13:06:44  Registered adapter: athena=1.6.4
# 13:06:44  Unable to do partial parsing because a project config has changed
# 13:06:44  Found 6 models, 6 seeds, 12 tests, 6 sources, 0 exposures, 0 metrics, 379 macros, 0 groups, 0 semantic models
# 13:06:44
# 13:06:50  Concurrency: 1 threads (target='dev')
# 13:06:50
# 13:06:50  1 of 6 START sql view model jaffle_shop.stg_customers .......................... [RUN]
# 13:06:52  1 of 6 OK created sql view model jaffle_shop.stg_customers ..................... [OK -1 in 2.04s]
# 13:06:52  2 of 6 START sql view model jaffle_shop.stg_locations .......................... [RUN]
# 13:06:52  2 of 6 ERROR creating sql view model jaffle_shop.stg_locations ................. [ERROR in 0.01s]
# 13:06:52  3 of 6 START sql view model jaffle_shop.stg_order_items ........................ [RUN]
# 13:06:54  3 of 6 OK created sql view model jaffle_shop.stg_order_items ................... [OK -1 in 1.99s]
# 13:06:54  4 of 6 START sql view model jaffle_shop.stg_orders ............................. [RUN]
# 13:06:54  4 of 6 ERROR creating sql view model jaffle_shop.stg_orders .................... [ERROR in 0.01s]
# 13:06:54  5 of 6 START sql view model jaffle_shop.stg_products ........................... [RUN]
# 13:06:56  5 of 6 OK created sql view model jaffle_shop.stg_products ...................... [OK -1 in 1.97s]
# 13:06:56  6 of 6 START sql view model jaffle_shop.stg_supplies ........................... [RUN]
# 13:06:56  6 of 6 ERROR creating sql view model jaffle_shop.stg_supplies .................. [ERROR in 0.02s]
# 13:06:56
# 13:06:56  Finished running 6 view models in 0 hours 0 minutes and 11.74 seconds (11.74s).
# 13:06:56
# 13:06:56  Completed with 3 errors and 0 warnings:
# 13:06:56
# 13:06:56    Compilation Error in model stg_locations (models\staging\stg_locations.sql)
#   Required var 'truncate_timespan_to' not found in config:
#   Vars supplied to stg_locations = {}
# 13:06:56
# 13:06:56    Compilation Error in model stg_orders (models\staging\stg_orders.sql)
#   Required var 'truncate_timespan_to' not found in config:
#   Vars supplied to stg_orders = {}
# 13:06:56
# 13:06:56    Compilation Error in model stg_supplies (models\staging\stg_supplies.sql)
#   'dbt_utils' is undefined. This can happen when calling a macro that does not exist. Check for typos and/or install package dependencies with "dbt deps".
# 13:06:56
# 13:06:56  Done. PASS=3 WARN=0 ERROR=3 SKIP=0 TOTAL=6
# aws-vault: error: exec: Failed to wait for command termination: exit status 1

ここでエラーが発生しました。以下の2件でエラーとなっている様子です。

  • Required var 'truncate_timespan_to' not found in config
  • 'dbt_utils' is undefined.

エラーに対する対処

1件目のRequired var 'truncate_timespan_to' not found in configについては、以下をdbt_project.ymlに追記して修正をします。

vars:
  truncate_timespan_to: "{{ current_timestamp() }}"

2件目の'dbt_utils' is undefined.は単純にパッケージが無いだけですので、以下をpackages.ymlに追記します。

packages:
  - package: dbt-labs/dbt_utils
    version: 1.1.1

その後、dbt depsで依存パッケージをインストールします。

dbt deps

# 07:47:32  Running with dbt=1.6.7
# 07:47:33  Installing dbt-labs/dbt_utils
# 07:47:33  Installed from version 1.1.1
# 07:47:33  Up to date!

dbt runの再実行

再度、dbt runでモデルを作成します。

dbt run

# 07:50:16  Running with dbt=1.6.7
# 07:50:16  Registered adapter: athena=1.6.4
# 07:50:16  Found 6 models, 6 seeds, 6 sources, 0 exposures, 0 metrics, 624 macros, 0 groups, 0 semantic models
# 07:50:16
# 07:50:22  Concurrency: 1 threads (target='dev')
# 07:50:22
# 07:50:22  1 of 6 START sql view model jaffle_shop.stg_customers .......................... [RUN]
# 07:50:24  1 of 6 OK created sql view model jaffle_shop.stg_customers ..................... [OK -1 in 2.06s]
# 07:50:24  2 of 6 START sql view model jaffle_shop.stg_locations .......................... [RUN]
# 07:50:26  2 of 6 OK created sql view model jaffle_shop.stg_locations ..................... [OK -1 in 1.87s]
# 07:50:26  3 of 6 START sql view model jaffle_shop.stg_order_items ........................ [RUN]
# 07:50:28  3 of 6 OK created sql view model jaffle_shop.stg_order_items ................... [OK -1 in 1.91s]
# 07:50:28  4 of 6 START sql view model jaffle_shop.stg_orders ............................. [RUN]
# 07:50:30  4 of 6 OK created sql view model jaffle_shop.stg_orders ........................ [OK -1 in 2.05s]
# 07:50:30  5 of 6 START sql view model jaffle_shop.stg_products ........................... [RUN]
# 07:50:32  5 of 6 OK created sql view model jaffle_shop.stg_products ...................... [OK -1 in 2.12s]
# 07:50:32  6 of 6 START sql view model jaffle_shop.stg_supplies ........................... [RUN]
# 07:50:34  6 of 6 OK created sql view model jaffle_shop.stg_supplies ...................... [OK -1 in 1.96s]
# 07:50:34
# 07:50:34  Finished running 6 view models in 0 hours 0 minutes and 17.49 seconds (17.49s).
# 07:50:34
# 07:50:34  Completed successfully
# 07:50:34
# 07:50:34  Done. PASS=6 WARN=0 ERROR=0 SKIP=0 TOTAL=6

stagingレイヤのモデルが作成されました。

current_timestampについて

先ほどdbt-project.ymlに追記した以下のcurrent_timestamp()についてです。

vars:
  truncate_timespan_to: "{{ current_timestamp() }}"

こちらはAthena上でクエリを実行する際には、以下のように解釈されて実行されます。

cast(now() as timestamp)

この辺りの動作はdbt-athenaの実装によるもののようです。

これを見る限り、table_typematerializedにより動作を変えるような仕組みが実装されているようです。

dbt-athenaが吸収しようとしてる部分が垣間見えますので、なるべくこういったcurrent_timestamp()などの定義済みのマクロを使用する方が恩恵を受けられるケースがありそうですね。

martsレイヤのモデル作成

ファイルの追加

Public Templateの以下にmartsレイヤのモデルのsqlファイルが格納されています。

ここからMetricflow以外のsqlファイルをmodels/marts配下にコピーします。

customers.sql
locations.sql
order_items.sql
orders.sql
products.sql
supplies.sql

materializedの設定

このmartsレイヤについてmaterializedを設定するため、dbt_project.ymlファイル以下を追加します。

models:
  jaffle_shop:
    staging:
      +materialized: view
    marts:
      +materialized: table

dbt runの実行でモデル作成

その後、dbt runでモデルを作成します。--select "marts"とすることにより、martsレイヤのモデルだけを作成することができます。

dbt run --select "marts"

# 09:53:22  Running with dbt=1.6.7
# 09:53:22  Registered adapter: athena=1.6.4
# 09:53:22  Found 12 models, 6 seeds, 6 sources, 0 exposures, 0 metrics, 624 macros, 0 groups, 0 semantic models
# 09:53:22
# 09:53:28  Concurrency: 1 threads (target='dev')
# 09:53:28
# 09:53:28  1 of 6 START sql table model jaffle_shop.locations ............................. [RUN]
# 09:53:42  1 of 6 OK created sql table model jaffle_shop.locations ........................ [OK 5 in 14.22s]
# 09:53:42  2 of 6 START sql table model jaffle_shop.order_items ........................... [RUN]
# 09:53:57  2 of 6 OK created sql table model jaffle_shop.order_items ...................... [OK 95368 in 15.07s]
# 09:53:57  3 of 6 START sql table model jaffle_shop.products .............................. [RUN]
# 09:54:11  3 of 6 OK created sql table model jaffle_shop.products ......................... [OK 10 in 13.89s]
# 09:54:11  4 of 6 START sql table model jaffle_shop.supplies .............................. [RUN]
# 09:54:25  4 of 6 OK created sql table model jaffle_shop.supplies ......................... [OK 65 in 14.23s]
# 09:54:25  5 of 6 START sql table model jaffle_shop.orders ................................ [RUN]
# 09:54:38  5 of 6 OK created sql table model jaffle_shop.orders ........................... [OK 59652 in 12.89s]
# 09:54:38  6 of 6 START sql table model jaffle_shop.customers ............................. [RUN]
# 09:54:51  6 of 6 OK created sql table model jaffle_shop.customers ........................ [OK 939 in 12.52s]
# 09:54:51
# 09:54:51  Finished running 6 table models in 0 hours 1 minutes and 28.49 seconds (88.49s).
# 09:54:51
# 09:54:51  Completed successfully
# 09:54:51
# 09:54:51  Done. PASS=6 WARN=0 ERROR=0 SKIP=0 TOTAL=6

martsレイヤのモデルが作成されました。

ここまでのレポジトリ

ここまでを実行したGitHubレポジトリを以下に公開しています。

今回扱わなかったこと

今回は簡単のため、以下についてはまだ取り込んでいません。今後取り扱おうと思います。

まとめ

いかがでしたでしょうか。本記事がdbt-athenaでdbtを始められる方の参考になれば幸いです。