dbt-athenaで既存のGlueテーブルをソーステーブルに使う

dbt-athena-communityで既存のGlueデータカタログをソーステーブルとして利用する方法や定義ファイルの書き方について確認しました。
2023.09.10

データアナリティクス事業本部 機械学習チームの鈴木です。

機械学習モデル作成用のデータマート作成に、dbt-athenaを使いたく、仕様について調べています。

dbtではsourceを使うことで既にデータウェアハウスにロードされているデータに対して名前をつけてDAGに取り込むことが可能です。もちろんdbt-athenaでも利用が可能です。

dbt-athenaの場合、Glueデータカタログ上の既存のGlueテーブルをソーステーブルとして使うことになりますが、定義ファイルの細かい書き方などちょっと気になるところがあったので試してみました。

この記事の内容について

Glueデータカタログ上の既存のGlueテーブルをsourceとして指定するためのymlファイルを作成し、ソーステーブルのデータを使ってモデルを作成しました。

特に、ymlファイルをどのように書くと、AthenaでどんなSQLが実行されるのかのイメージを持ちたかったため、ymlファイルとクエリ履歴の比較もしました。

環境構築

以前公開した以下の記事の方法でEC2上にdbt-coreとdbt-athena-communityをインストールして検証しました。

dbtのバージョンは以下になります。

  • dbt Core:1.5.6
  • dbt-athena-community:1.5.1

Glueテーブルは以下のように、S3バケットに配置したUCI Machine Learning RepositoryのIris Data Setを検索できるテーブルを作成しておきました。

作成しておいたGlueテーブル

このデータセットは、下記リンクにて公開されています。

https://archive.ics.uci.edu/ml/datasets/iris

やってみる

1. ソーステーブルを定義する

models/iris.ymlを以下のように作成しました。

models/iris.yml

version: 2

sources:
  - name: iris_raw
    database: awsdatacatalog 
    schema: cm-nayuts-sample-db
    tables:
      - name: iris

プロパティは以下のガイドを参考にしました。

nameおよびtablesはほかのコネクタの場合と同様に考えればよかったのですが、迷ったのはdatabaseschemaでした。

この2つについては、profiles.ymlに記載する内容を説明した、dbt-athenaレポジトリのConfiguring your profileに記載の事項と同様で良いだろうと考え、databaseにはawsdatacatalogを、schemaにはGlueデータベース名を設定しました。

2. ソーステーブルを参照するモデルを定義する

続いて、集計後のマートとして、モデルを以下のiris_mart.sqlのように定義しました。

models/iris_mart.sql

select
    class,
    avg(sepal_length) as avg_sepal_length,
    avg(sepal_width) as avg_sepal_width,
    avg(petal_length) as avg_petal_length,
    avg(petal_width) as avg_petal_width
from {{ source('iris_raw','iris') }}
group by class

{{ source('iris_raw','iris') }}としてソーステーブルを指定しました。

なお、今回はプロジェクトのdbt_project.ymlファイルにて、modelsディレクトリのmaterializedtableを指定しています。

3. モデルの作成を実行する

モデルを作成しました。

dbt run

Athenaのクエリ履歴を確認すると、以下のように2つのSQLが実行されていました。

-- /* {"app": "dbt", "dbt_version": "1.5.6", "profile_name": "test_project", "target_name": "dev", "node_id": "model.test_project.iris_mart"} */

  
    create table "awsdatacatalog"."cm-nayuts-sample-db"."iris_mart"
  with (
    table_type='hive',
    is_external=true,external_location='s3://s3_data_dirで指定したパス/cm-nayuts-sample-db/iris_mart/c1a7d67b-b6fc-4286-ba74-6511204e99f5',
    format='parquet'
  )
  as
    select
    class,
    avg(sepal_length) as avg_sepal_length,
    avg(sepal_width) as avg_sepal_width,
    avg(petal_length) as avg_petal_length,
    avg(petal_width) as avg_petal_width
from "awsdatacatalog"."cm-nayuts-sample-db"."iris"
group by class

s3_data_dirで指定したパス~/.dbt/profiles.ymlで指定したs3_data_dirキーのバリューのことです。

alter table `cm-nayuts-sample-db`.`iris_mart` set tblproperties ('classification' = 'parquet')

1つ目のSQLでハイライトしたように、databaseschemaの値が使われています。

マートテーブルは以下のように作成されました。

作成されたマート

空行が入っているのはソーステーブルのデータセットに元々空行があるためです。

4. ソーステーブルの定義を変えてSQLを確認する

以下は少し細かい確認ですが、databaseの記載によって、実行される1つ目のSQLがどう変わるのか気になったので確認しました。

まずは指定しないパターンです。

models/iris.yml

version: 2

sources:
  - name: iris_raw
    # database: awsdatacatalog 
    schema: cm-nayuts-sample-db
    tables:
      - name: iris

以下のようにデフォルト値としてawsdatacatalogが設定されました。

-- /* {"app": "dbt", "dbt_version": "1.5.6", "profile_name": "test_project", "target_name": "dev", "node_id": "model.test_project.iris_mart"} */

  
    create table "awsdatacatalog"."cm-nayuts-sample-db"."iris_mart"
  with (
    table_type='hive',
    is_external=true,external_location='s3://s3_data_dirで指定したパス/cm-nayuts-sample-db/iris_mart/fae19913-af30-4fe6-9547-87fe13bafc1b',
    format='parquet'
  )
  as
    select
    class,
    avg(sepal_length) as avg_sepal_length,
    avg(sepal_width) as avg_sepal_width,
    avg(petal_length) as avg_petal_length,
    avg(petal_width) as avg_petal_width
from "awsdatacatalog"."cm-nayuts-sample-db"."iris"
group by class

次にawsdatacatalog以外を指定したパターンです。

models/iris.yml

version: 2

sources:
  - name: iris_raw
    database: dummy 
    schema: cm-nayuts-sample-db
    tables:
      - name: iris

指定した値が設定されました。awsdatacatalog以外のデータソースを使いたいときにも使用できますね。

-- /* {"app": "dbt", "dbt_version": "1.5.6", "profile_name": "test_project", "target_name": "dev", "node_id": "model.test_project.iris_mart"} */

  
    create table "awsdatacatalog"."cm-nayuts-sample-db"."iris_mart"
  with (
    table_type='hive',
    is_external=true,external_location='s3://s3_data_dirで指定したパス/cm-nayuts-sample-db/iris_mart/65a38014-9696-43cb-bac6-776b6b350b62',
    format='parquet'
  )
  as
    select
    class,
    avg(sepal_length) as avg_sepal_length,
    avg(sepal_width) as avg_sepal_width,
    avg(petal_length) as avg_petal_length,
    avg(petal_width) as avg_petal_width
from "dummy"."cm-nayuts-sample-db"."iris"
group by class

最後に

dbt-athena-communityで既存のGlueデータカタログをソーステーブルとして利用する方法や定義ファイルの書き方について確認しました。

dbtの基本的な機能ですが、dbt-athenaでも使えることが確認できました。これにより、既にデータレイクに連携されているデータからモデルを作成することができますね。

参考になりましたら幸いです。