🔖
dbtのパイプライン上でBQMLを使いたいんじゃ!!
この記事はdbt Advent Calendar 2022の12月3日の記事です!
タイトルはぜひテレビ千鳥の大悟を想像しながら読んでください
概要
-
社内で用いるための学習モデルを簡単にバッチ実行するにはどうしたらいいかな?というのを調査したものになります
- プロダクトで使うための学習モデルは想定していません
-
dbtのパイプラインと共にBQMLを使っていくにはどのように作っていくといいか実験しました
解決手法と選定理由
- 所属するチーム、組織のケイパビリティ的にBQMLがフィットと判断しました
- 特徴量の生成をdbtで管理できる
- 「Vertex AIでモデルをホストして〜」みたいなのは現状のチームにはtoo much
- 使うモデルが複雑なものではない(今の所せいぜいGBDT)
- DSとしてリソースを確保できるのか現状微妙なので、BQML経由でAuto ML tablesを使う余地がある
以上の理由よりBQMLを選定しました
技術検証のゴール
- データ基盤のテーブルと、特徴量やモデル用のテーブルを別のデータセットで管理できるようにする
- これをdbtのワークフローの中で解決できるのか
- dbtのワークフローの中でBQML実行できるようにする
- 通常viewやtableを作る前提なので
CREATE TABLE
などのDDLがついてコンパイルされてしまう - suffixでモデルの学習日とか入れられると後々の検証に役立ちそう
- 通常viewやtableを作る前提なので
ゴールイメージ
(実験場であるkawaii-dbtで実験してます)
- modelsの下にDWH用のディレクトリとML用のディレクトリを分ける
- suffixでディレクトリ名がつく
- 指定すればsuffixがつくし、指定しなければつかない(
kawaii-dbt
のままがいいということもできる)
- 指定すればsuffixがつくし、指定しなければつかない(
- モデルのsuffixに実行日時をつける
ゴールとしないこと
- 学習モデルやハイパーパラメータの検討
結果
データセットも分けられるし、dbtでBQMLも実行できる
喜ぶ大悟
データ基盤のテーブルと、特徴量やモデル用のテーブルを別のデータセットで管理できるか
- これはもう少し詳細に考えると「dbtのワークフローの中でdatasetを分けて出力できるか」になります
方法
公式のドキュメントにもあるCustom Schemaを使えば実現できます
dbt_project.ymlの修正
-
dbt_project.yml
のmodels
プロパティを追加する
name: kawaii_dbt
version: '1.0.0'
config-version: 2
profile: 'kawaii-dbt'
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]
target-path: "target"
clean-targets:
- "target"
- "dbt_packages"
models:
kawaii_dbt:
dwh:
+schema: dwh
+ tags:
- "dwh"
ml:
+schema: ml
+tags:
- "ml"
-
kawaii_dbt
の部分はname
プロパティになります(必須です)、その下のdwh
とml
がディレクトリ構成で言うmodels/
の子ディレクトリに当たる- なんかうまくパースできない時のトラブルシューティングはこちら
-
tags
プロパティはDWHの部分とMLの部分を分けて実行したい時ように追加してるだけで、ここの文脈ではなくても大丈夫です- でも
dbt run -s tag:ml
でML部分だけ実行とかしたくなりそうじゃない?
- でも
custom schemaをオーバーライドするmacroの用意
-
schema
ってのはBigQueryではdatasetのことです -
generate_schema_name.sql
というファイル名でmacrosディレクトリ配下にmacroを用意する必要があります(おそらくファイル名は重要ではなく、macro名が重要) - どこのschemaに吐き出すのかというのを設定するところをオーバーライドするmacroという理解です
{% macro generate_schema_name(custom_schema_name, node) -%}
{%- set default_schema = target.schema -%}
{%- if custom_schema_name is none -%}
{{ default_schema }}
{%- else -%}
{{ default_schema }}_{{ custom_schema_name | trim }}
{%- endif -%}
{%- endmacro %}
以上!
なんかうまくいかんって時に見るところ
[WARNING]: Configuration paths exist in your dbt_project.yml file which do not apply to any resources.
There are 1 unused configuration paths:
- models.kawaii-dbt.ml
ってwarningが出てきてたらdbt_project.yml
をうまくパースできていません
dbt_project.yml
をいじって、dbt parse
を実行してwarningが出なくなるまで頑張りましょう
これ見ながら頑張ってください(再掲)
dbtのワークフローの中でBQML実行できるのか?
- 結論、できる
- 日付をsuffixにする部分もできる(ただし癖あり)
方法
dbt_ml
packageを使う
- 開発が盛んというわけでもないのと、メジャーバージョンがリリースされてるわけではないので、使う際の影響は考えた方がいいのかなと思っています
alias
を渡す
configでBQMLの部分になります
あとでalias
に応じてモデル名を動的に与えたいのでalias
を指定しています
{{
config(
alias='train',
materialized='model',
ml_config={
'model_type': 'LINEAR_REG',
'max_iterations': 10,
'input_label_cols': ['duration_minutes']
}
)
}}
select *
from {{ ref("feature_label") }}
custom aliasをオーバーライドするmacroの用意
-
alias
ってのがBigQueryではtableのことです -
generate_alias_name.sql
というファイル名でmacrosディレクトリ配下にmacroを用意する必要があります - schemaと同じでオーバーライド用のmacroです
- この中で動的にaliasをいじっています
- aliasがtrainって名前だったらsuffixに今の日時を付与しています
{% macro generate_alias_name(custom_alias_name=none, node=none) -%}
{%- if custom_alias_name is none -%}
{{ node.name }}
{%- elif custom_alias_name == 'train' -%}
{% set now = modules.pytz.timezone('Asia/Tokyo').localize(modules.datetime.datetime.now()) %}
{% set now_formatted = now.strftime('%Y%m%d%H%M') %}
{{ custom_alias_name | trim }}_{{ now_formatted }}
{%- else -%}
{{ custom_alias_name | trim }}
{%- endif -%}
{%- endmacro %}
以上!
困った時に見るとこ
- 一回実行すると、モデルの依存関係をキャッシュとして保持しているのか(推測)、二回目の実行がこけることがありました
- そういう時はtargetディレクトリ消して実行するとうまくいくはず
- それでもダメな時は
dbt clean
してみてね
- それでもダメな時は
- それでもダメならどこか間違ってるのでtypoとかないか確かめてね
そのほかに考慮しないとなということ
- 前提、この取り組みはまだ始まる前なので、実際に使ってみたら使いにくい!変える!とかあるかもしれません
- 特徴量に作成日時のカラムを追加して、何かあった時に調査できるようにしたいと思っています
- 弊社ではdbt-coreをCloud Buildでキックしていて、上限が24時間なのですが学習をdbtのパイプラインで回す場合は学習時間を把握してタイムアウトを設定する必要があると思います
まとめ
- BQMLまわりを調査してたけれど、一番大きい収穫は
Custom schema
とCustom alias
の習得でした - 現状dbtのパイプラインにBQMLを載せるにはpackage使うしか方法が見当たらなかったのですが、dbtのワークフローの中でDDLを手軽に実行できるといろんなことができていいなと思いました
- もし他により良い方法があったらコメントください
Discussion