ギークなエンジニアを目指す男

機械学習系の知識を蓄えようとするブログ

DataformをGoogle Cloud上から触ってみる(rawデータから集計テーブルを作るまで)

たかぱい(@takapy0210)です。

正月にGoogle CloudのDataformをゴニョゴニョ触っていたので、その備忘録を残しておこうと思います。

Dataformとは

SQL likeなコード(SQLX)でテーブルやビュー作成クエリを記述することで、テーブル間の依存関係を管理することができるデータモデリングツールです。同じようなツールではdbt*1が有名だと思います。

cloud.google.com

Dataformは、以前は独立したSaaS サービスでしたが、2020年12月にGoogle傘下に加わり、2023年6月6日にGAになりました。 cloud.google.com

2024/01 現在はBigQueryデータのモデリングツールとして、Google Cloud 管理コンソールから実行できるようになっています。

dbtとの違いは...?

Googleで検索するといくつか記事がヒットすると思いますが、

  • dbtは機能が豊富でコミュニティも大きいが、学習コストがそこそこ高い
  • Dataformは学習コストや運用コストは低い(Google Cloud上であれば無料で実行できる)が、dbtと比べると機能面で劣る

ということが言われているかと思います。

今回は個人開発で使用する目的なので、学習コストと運用コストが低いDataformを導入しました。

使用したデータ

今回は僕が趣味で集めている都内のマンション情報のデータが既にBigQueryにあるので、そのRawデータから区ごとの平均坪単価などをDataformで集計して、データマートに自動的に保存するところまでやってみます。

データのイメージ

実際に動かしてみる

以下のクイックスタート通りに動かしてみると、全体的な動きがある程度理解できるかと思います。

cloud.google.com

実際の開発画面

基本的な設定を記載する「dataform.json」

開発ワークスペースを初期化するとデフォルトでいくつかファイルが生成されますが、基本的な設定は dataform.json に記述されています。

{
  "defaultSchema": "dataform",
  "assertionSchema": "dataform_assertions",
  "warehouse": "bigquery",
  "defaultDatabase": "hoge",
  "defaultLocation": "asia-northeast1"
}
  • defaultSchema: Dataform がアセットを作成する BigQuery データセットを指定する
  • assertionSchema: Dataform がアサーション結果を含むビューを作成する BigQuery データセットを指定する
  • warehouse: Dataform がアセットを作成する BigQuery へのポインタ。”bigquery” を指定する
  • defaultDatabase: Dataform がアセットを作成する Google Cloud プロジェクトIDを指定する
  • defaultLocation: デフォルトの BigQuery データセットのロケーションを指定する

Dataformのディレクトリ構成はどうするのが良いのか

買収前の従来のDataformのドキュメント*2には、definitions ディレクトリ配下に「Sources」、「Staging」、「Reporting」を用意することが推奨されていますが、Google Cloudのドキュメントには、ベストプラクティスとして以下のような構成が推奨されています。

  • sources: データソース宣言を格納
  • intermediate: データ変換ロジックを格納
  • outputs: 出力テーブルの定義を格納
  • extras - 追加のファイルを格納(省略可)

cloud.google.com

今回はGoogle Cloudのベスプラに倣い、以下の構成で開発しました。

Google Cloud上の開発画面から見るディレクトリ構成

実際に記述するsqlxのコード

今回は以下の2つを追加しています。

  • definitions/sources/mansion.sqlx
  • definitions/outputs/day_aggregated_by_city.sqlx

definitions/sources/mansion.sqlx

ここではDataformで管理するテーブルを定義します。declarationを使ってテーブルを定義するのみで集計クエリなどは記載しません。

config {
    type: "declaration",
    database: "hoge",
    schema: "lake",
    name: "mansion"
}

Dataformのクエリで直接 SELECT * FROM project-id.dataset.table のように書くことはできますが、直接参照だとデータリネージで自動的に可視化されないので利用するテーブルはここで定義することをお勧めします。

declarationで定義しておくと SELECT * FROM ${ref(test_table)} という書き方で参照できます。

cloud.google.com

definitions/outputs/day_aggregated_by_city.sqlx

ここでは、データレイク(マンション情報)からデータを集計して、データマートに新しいテーブルを作成するクエリを定義します。

前述した通り、前提となるテーブルを「${ref("mansion")} 」という記法で参照できます。Dataform におけるテーブル間の依存関係管理はこれを書くだけでOKです。

パーティションやクラスタ*3の指定も configで行えます。

config {
    type: "table",
    database: "hoge",
    schema: "mart",
    columns: {
        city: "市区町村ラベル(e.g. chuoku)",
        count: "レコード数",
        avg_price: "物件価格(万円) - 平均",
        avg_price_per_unit: "坪単価(万円) - 平均",
        avg_price_per_square_meter: "平米単価(万円) - 平均",
        stddev_price: "物件価格(万円) - 標準偏差",
        stddev_price_per_unit: "坪単価(万円) - 標準偏差",
        stddev_price_per_square_meter: "平米単価(万円) - 標準偏差",
        meta_execution_date: "処理実行日(yyyy-mm-dd)",
    },
    bigquery: {
        partitionBy: "meta_execution_date",
        clusterBy: ["city"]
    },
}

SELECT
  city,
  COUNT(*) AS count,
  ROUND(AVG(price_yen/10000), 2) AS avg_price,
  ROUND(AVG(price_per_unit/10000), 2) AS avg_price_per_unit,
  ROUND(AVG(price_per_square_meter/10000), 2) AS avg_price_per_square_meter,
  ROUND(STDDEV(price_yen/10000), 2) AS stddev_price,
  ROUND(STDDEV(price_per_unit/10000), 2) AS stddev_price_per_unit,
  ROUND(STDDEV(price_per_square_meter/10000), 2) AS stddev_price_per_square_meter,
  meta_execution_date,
FROM
  ${ref("mansion")}
WHERE
  0 = 0
  AND city IS NOT NULL
GROUP BY
  city,
  meta_execution_date

ここまでで、手動で新規テーブルを作成する準備は終わりです。コンソール上から手動実行すれば、BigQueryの mart 配下にテーブルができます。

テーブルが作成されている様子

作成されたデータ

スケジュール実行する

以下の手順に沿って設定し、自動化を行います。

cloud.google.com

手順は大きく分けて「リリース構成」の作成と、「ワークフロー構築」の2ステップあります。

リリース構成とは、リポジトリを定期的にコンパイルしてリリースする頻度を指定するものです。
ワークフロー構築とは、実際に動くワークフローを指定するものです。

注意点として、公式ドキュメント*4にも記載されているように、リリース構成で指定した時間より、ワークフロー構築で指定する実行時間を、最短でも1h開けておく必要があるようです。

Dataform が対応するリリース構成で最新のコンパイル結果を確実に実行するには、コンパイル結果の作成時刻とスケジュールされた実行時刻の間に少なくとも 1 時間の間隔を設けます。

実際の設定画面

設定後、時間が過ぎると正しく動いていることが確認できました。
ワークフロー実行のログも、コンソール上から確認できます。

ワークフロー実行のログ

Githubと連携してコード管理する

最後にGithubとの連携を行い、コードをリポジトリで管理できるようにします。

こちらも公式ドキュメントが出ているので、基本的にはこの通りに設定すれば問題なく動くと思います。

cloud.google.com

おわりに

触ってみた感じ、WebUIでの開発環境がとっつきやすく、自動フォーマットもボタン1つで行なってくれるので開発効率は良さそうに感じました。

増分モデルなども簡単に実装できそうなので、この辺もいじっていきたいと思います。

cloud.google.com