こんにちは。那須野拓実です。
Dataformでデータパイプラインを作るぞというときに、一通りの流れが分かるような資料があると便利だなと思ったので書いてみます。
主な内容としては、実際の構築作業の流れを洗いつつ、人によって諸説あるコーディングスタイルを確認したうえで、運用作業の流れを洗っていき、最後におまけとして開発環境を用意する方法についても確認します。
そもそもDataformとは何かの説明について昔の記事に説明を譲りますが、Dataformの構成がどのようになっているか、どういったオブジェクト概念があるかは再確認しておきたいです。
昔の記事からの抜粋したイメージがこちらです。これを押さえたうえで、実際の作業の流れを見ていきましょう。
Dataformで実装するうえで、まずは以下6点を注意事項として頭に入れておきたいです。
そのうえで、具体的な構築作業の流れは以下をイメージしましょう。
実際に構築作業を行う際、まずはDataformでデータパイプラインを作ろうとしたときに最初にぶつかるであろう、コーディングスタイルの基本中の基本を見ていきます。
人によって諸説あるところですし、あくまで現時点での個人的な見解なので、ご留意のうえお読みください。
→スネークケースで書く。
変数を作るときにどの表記方法を使うかは人によって判断が分かれるところですし、データソースによっては元から決まっていることもありますが、やはり揃えられるなら揃えたいところです。
データベースによっては大文字小文字を区別しない点を鑑みるに、やはりスネークケースでまとめておくのが無難でしょう。なお、データソースとなるテーブルはスネークケースにならない場合はあるので、それらは妥協します。
→大文字に揃える。
SQLではSELECT句やWHERE句などの句は大文字で小文字でも機能します。なので、人によってどちらで書くかに違いがあったり、人によっては敢えて揃えずバラバラということもあるでしょう。
ただし、前述の通り変数をスネークケースで揃えた場合、句を大文字に揃えることで変数と句の区別がパッと見で判断しやすくなるため、句を大文字にする方がよいでしょう。
→2個に揃える。
コーディングをする際は構造を分かりやすくするためにタブを使いますが、タブの幅がスペース相当で2個なのか4個なのかは人によって判断が分かれるところでしょう。
この点について、Dataformでは初期設定が2個であるため、原則として2個にするのが無難でしょう。
→行末に置く。
変数などカンマ区切りにする場合、変数ごとに改行するのはほぼほぼ全員がやっていることかと思いますが、カンマを行末に置くか行頭に置くかは微妙に好みが分かれるところだと感じます。
ただ、オーソドックスなやり方としてはやはり行末に置く形でしょうし、Dataformのサンプルもそうなので、行末にカンマを原則としましょう。
1 2 3 4 5 6 |
SELECT column_a, column_b, column_c FROM {input_table} |
→半角スぺースを入れる。
可読性向上のため、コロンやカンマの後に同じ行で続く場合は半角スペースを入れましょう。
1 2 3 4 5 |
config { type: 'table', description: 'Sample table definition is here.', tags: ['tag1', 'tag2', 'tag3'] } |
→シングルクオテーションを基本とする。
文字列を表すクオテーションはシングルクオテーション(')とダブルクオテーション(")の2種類あります。どちらを使うかは宗教戦争のような側面があるでしょう。
しかし、ことDataformに限っては、実行詳細を確認するときにシングルだと赤字で強調される一方で、ダブルの場合は黒字のままという仕様があります。分かりやすさ重視で言えば、シングルクオテーションを基本とするのがよさそうです。
→大型プロジェクトなら個別ファイルで明示。それ以外ならデフォルトを駆使しながらsourcesだけ明示する。
project(database)とdataset(schema)の定義を個別のSQLXファイルで書くことを徹底するか、workflow_settings.yamlで適切に書いてあるから省略するかも、人によっては判断が分かれるところでしょう。
作成するテーブル群を元テーブル(sources)と加工テーブル(output)に分けたときに、outputを1つのデータセットで管理できるなら
という使い分けによる省エネが良さそうです。outputが複数のデータセットにわたる大型のプロジェクトの場合、省略する場合としない場合とが混在すると状況把握が難しくなるので全てに書く方が良いと考えます。
→ファイル名を正しく使い、config.nameは極力使わない。
nameについては、デフォルトではファイル名を参照するという仕様がある一方で、もちろんconfig.nameによる明示もできます。
人が読むにはconfig.nameにある方が一貫性があって良い気はしますが、原則としてファイル名=nameとすべきであるし、ズレていると思わぬミスを引き起こすリスクがあることから、ファイル名を正しく使ってconfig上は省略するという運用が望ましいでしょう。
→全てのテーブル、カラムにつける。
作成するテーブルやカラムには、原則として全てにdescriptionをつけて、他の人がBigQuery上でスキーマ定義を見て最低限分かるようにしましょう。
続いて運用作業です。
SQLを書き換えなくてよいワークフローが完成しているという前提で、運用段階で発生する主な作業を9つに整理しました。
なお、できることが多岐にわたり、かつやればやるほど管理コストが上がっていくため、実務上は現場に求められるSLAをもとに費用対効果に見合う運用として再設計する必要がある点には留意します。
それでは1つずつ見ていきましょう。
全てのデータが自動同期されていれば不要ですが、実際には少なくないプロジェクトでデータの手動投入が発生します。その場合は定期的に、指定されたデータを指定された場所(クラウドストレージやスプレッドシートなど)に手動で格納する運用を設計しましょう。
なお、その後は、自動ワークフローの実行による反映を待つ場合と、手動ワークフローを速やかに実行する場合とに分かれます。現場の必要とするスピード感に合わせた運用を設計しましょう。
前項のデータの手動投入の後のデータ更新も含め、他の手作業のワークフローとの連携があって実行タイミングを定義しづらいデータ更新は手動での実行となります。
手作業はリスクが大きいため、実行履歴を残して漏れなく作業できていることを確認できるようにし、また作業前後の状況をファクトとして最低限確認できるよう作業結果を残しておくようにしましょう。
Dataformであれば多くのワークフローは自動で実行されるわけですが、常に正しく実行されるというわけでもありません。時にはエラーが起きて失敗します。重要なのは、エラーが起きた際にその事実を速やかに把握し、状況を的確に捉えたうえで、問題があれば原因究明し、必要に応じて解決を行えるようにしておくことです。
まず、ログベースの指標にてエラー数を検知できるようにしましょう。具体的には、指標タイプ=Counterにて、フィルターにてBigQueryのエラーないしDataformの定期実行エラーを検知できるようにしましょう。
1 2 3 4 5 6 7 8 9 |
# BigQueryのエラー resource.type="bigquery_resource" protoPayload.jobInsertResponse.resource.jobStatus.errorResult:* # Dataformの定期実行エラー resource.type="dataform_workspace" protoPayload.serviceName="dataform.googleapis.com" protoPayload.metadata.triggerType="SCHEDULED" protoPayload.response.state="FAILED" |
その後しばらくすると指標が生成され、Metric Explorerにてグラフを確認できるようになります。
続いて通知が来るようにするために、アラートにてポリシーを作成しましょう。例えば先ほどのbigquery_error_countでは、ローリングウィンドウ=5分、ローリングウィンドウ関数=SUM、Condition Types=Threshold(閾値)、Alert trigger=任意の時系列の違反、しきい値 0 より上に設定し、最後に通知先と通知件名、そしてアラートポリシーの名前を設定して完了です。
ちなみに通知先はGoogleアカウントのメアドが基本ですが、Google ChatやSlack、Webhooks、SMSなども選べるので、状況に合わせて利用するのと、リスク防止の観点では複数のチャネルを設定するとよいでしょう。
また、エラー通知があった場合に、誰がどのように対応するかについても重要です。組織としての妥当なSLA(サービス・レベル・アグリーメント)を定義したうえで、体制を整えておきましょう。
なお、Metric Explorerは2025年3月時点では無料で使えるようですが、2026年からはお金がかかるようです。画面を見た感じだと月1.5ドルなので留意しておきましょう。
ワークフローがエラー無く動いてダッシュボードにデータが表示されていても、データソースに問題があるとまともに使うことができません。たとえば異常値が入って集計値がまともに見れなくなったり、欠損値が入って推移や変化率が見えなくなったり、データが重複したために指標が水増しされたりなどです。
こういった問題を検知するには、現場の必要とするSLAを考慮して以下の3点でのチェックを検討しましょう。一般的には上のものほど採用率が高いと思います。
ダッシュボードに適切にデータが表示されて使えていたとしても、その効果に見合わないほどのお金がかかりすぎていたとしたら運用としては合格にはなりません。そう、BigQueryは「お金を溶かす」ことがあります。
お金を溶かさないために、差分更新をはじめとした工夫によって「溶かしづらい」データパイプラインを構築することはもちろん大前提ですが、動くデータを集計するパイプラインは問題が起きないか常に監視しておく必要があります。
具体的には、以下の3点を対策しておきましょう。
データ分析ではデータをある程度のまとまりに区切って集計することが多く、現場の意図に合った集計のためにマスターデータ(例えば商品マスターや店舗マスター、URLマスター、組織マスター、従業員マスターなど)を用意しておくことが多いです。ほとんどの場合、これらマスターデータは勝手には更新されてくれないので、現場の動きに合わせた更新業務が発生します。
マスターデータは日常的な更新は発生しないという前提ですが、月に1回や四半期に1回、半年に1回、年に1回などの頻度で発生しうるため、現場のスピード感に合わせた更新体制を整え、またイレギュラーな更新が必要になる際に作業ワークフローも整えておきましょう。
必要に応じて、マスターデータの切り替えをテストできるように開発環境を整えておくことや、マスターデータの参照も開発環境/本番環境で切り替えられるようSQLの実装を工夫しておくことも考えてましょう。
現場ユーザーからは定期的にフィードバックをもらえるようにしましょう。
というのも、ダッシュボードは現場ユーザーが使ってなんぼなわけで、もし何らかの理由で使えていなくなっているとしたら、データベースやデータパイプラインはただの金食い虫に成り下がるからです。
なお、メアドやチャットなどで問い合わせ窓口を用意すればよいだけではないかもしれません。気軽に言い合える関係でなければ、問い合わせ窓口を用意したところで実際には連絡が来ずに放置されて、そのまま運用がフェードアウトするケースも散見されます。
関係性が出来上がっていないような状態であったり、対象ユーザーが広範にわたる場合は、運用側から能動的にフィードバックを取得しに行く体制を整えることも検討しましょう。
前項とも関連しますが、使われていないダッシュボードは無意味どころか負債です。そして「ちゃんと使われているかどうか」を確認するには、利用状況をトラッキングする必要があります。
利用状況は、できればレポート単位であったり、できれば部門単位や個人単位でトラッキングできることが望ましいです。以下の3つの方法が考えられますが、実務上は1番で妥協することが多いでしょう。
一度作ったダッシュボードはそのままずっと使い続けられるということはほとんどありません。ダッシュボードを使うなかで「より良いデータ活用に気づく」こともあれば、「現場の状況が変わって別の分析を必要とするようになる」こともあります。そういった変化は定期的に発生するため、ダッシュボードの定期的な改修対応が必要になってきます。
前述の4~8あたりをしっかり取り組んでいれば、改修内容の把握は十分にできるのではないかと思いますが、実際に改修対応をするには、以下のような点に目を配らせておく必要があります。
最後におまけとして、開発環境のための実装について書いてみます。
冒頭に書いたように、ミッションクリティカルなプロジェクトであったり、チームでの開発であったりする場合、開発したデータパイプラインのテストは本番環境ではやらず、開発用の環境を別途用意した方が良いです。
Dataformで開発環境を用意するにはいくつかの方法がありますが、環境を用意する目的感として
という前提があるのであれば、コンパイル変数の活用で実装が可能です。具体的には以下のようなイメージです。
1 2 3 4 |
defaultDataset: {dev_dataset_name} vars: ENVIRONMENT: 'dev' PROD_DATASET: '{prod_dataset_name}' |
1 2 3 4 5 6 |
module.exports = { output_dataset: dataform.projectConfig.vars.ENVIRONMENT === 'prod' ? dataform.projectConfig.vars.PROD_DATASET : dataform.projectConfig.defaultSchema }; |
1 2 3 |
config { schema: constants.output_dataset } |
この方法の一番のメリットは、やろうと思えばconstants.jsにて出力先のデータセットを複数用意できる点、つまり、outputとintermediateを切り分けられる点です。柔軟性がとにかく高いです。
なお、コンパイル変数による開発環境にも2つ注意点があります。
これらの点には注意しつつ、開発を進めていきましょう。
以上、Dataformによるデータパイプラインの構築と運用の進め方ということでまとめてみました。
この記事を読みつつ、以前の記事である2つを読むと、Dataformのスタートをぼちぼち切れるのではないかなと思います。これらの記事がいつかどなたかの参考になれば幸いです。