0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bigquery Dataform 〜テクニック編〜

Last updated at Posted at 2025-12-03

PONOS Advent Calendar 2025 4日目の記事です。

初めに:eyeglasses:

BigQueryでのデータ変換を飛躍的に効率化するDataform。
今回は実践的なテクニックを紹介します。

確実な環境分離テクニック 🛡️

DataformはGit管理を通じて1つのプロジェクト内で開発(devブランチなど)と本番(mainブランチなど)を管理できますが、テーブルの保存先や処理ロジックを環境ごとに分ける必要があります。

テクニック1:コンパイル設定で環境全体を切り替える

この方法は、テーブルの保存先データセットや、処理のサンプリングON/OFFなど、プロジェクト全体の挙動を環境に応じて自動で切り替える最も堅牢な手法です。

📁 workflow_settings.yaml による環境定義

workflow_settings.yaml は、プロジェクト全体で共有するデフォルト設定と、特定の実行環境(devなど)でそれを上書きする コンパイル設定 を定義します。

✅ 実装例:workflow_settings.yaml

以下の YAML ファイルを Dataform プロジェクトのルートディレクトリに配置することで、ご要望の設定が再現されます。

# ----------------------------------------------
# 1. 共通のデフォルト設定(本番環境のベース)
# ----------------------------------------------
default:
  defaultDatabase: "data-project-prd"      # 本番プロジェクト
  defaultSchema: "dataform_prod"           # 本番データセット
  
  # vars: SQLXコード内で参照するカスタム変数
  vars:
    environment: "prod"
    is_sampling_enabled: false             # サンプリングを無効化(全量データ)
    
# ----------------------------------------------
# 2. 開発環境 (Dev) のコンパイル設定 (Overrides)
# ----------------------------------------------
compilation_overrides:
  # Dataform コンソールや API で "dev" を指定すると、以下の設定でコンパイルされます
  dev:
    defaultDatabase: "data-project-dev"    # 開発プロジェクトに上書き
    defaultSchema: "dataform_dev"          # 開発データセットに上書き
    
    vars:
      environment: "dev"
      is_sampling_enabled: true            # 開発時はサンプリングを有効化

この設定により、dev設定でワークフローを実行すると、自動的にすべてのテーブルがdata-project-dev.dataform_devに作成されます。

💡 SQLXでのロジックの切り替え
workflow_settings.yamlで定義した変数は、SQLX内のJavaScriptブロックで参照可能です。これにより、本番環境でのみサンプリングを無効化し、クエリコストを削減できます。

✅ SQLXでの変数参照

config {
  type: "table"
}

-- Dataformの変数を参照
<script>
  // yamlで設定した vars.environment を参照
  const isDev = dataform.projectConfig.vars.environment === "dev";
  // または、vars.is_sampling_enabled を直接参照
  const isSamplingEnabled = dataform.projectConfig.vars.is_sampling_enabled;
</script>

SELECT
  log_id,
  user_id,
  ...
FROM
  `raw_data.access_logs`
WHERE
  log_timestamp IS NOT NULL
-- 開発環境の場合のみ、サンプリングする
<% if (isDev) { %>
  AND user_id IN (SELECT user_id FROM `raw_data.dev_sample_users`)
<% } %>

テクニック2:コード内でソースを動的に切り替える

参照する外部ソース(例:GA4、サードパーティDB)のデータセットIDやプロジェクトIDが、実行環境によって変わる場合に有効な方法です。

BigQueryの組み込み変数 @@project_id を使って、現在実行中の環境を判定し、参照先のデータセットを動的に決定します。

✅ 実装例:GA4データソースの動的切り替え

definitions/events_purchase.sqlx
config {
  type: "operations" -- INSERT処理を行うため、operationsとして定義
}

DECLARE GA_dataset STRING;

SET GA_dataset = (
  CASE 
    WHEN @@project_id = "project-id-dev" THEN "analytics_AAABBBCCC" -- 開発GAデータセット
    WHEN @@project_id = "project-id-prod" THEN "analytics_XXXYYYZZZ" -- 本番GAデータセット
  END
);

-- GAからイベントデータを取得し、集計テーブルに追記
EXECUTE IMMEDIATE FORMAT("""
    INSERT INTO `analytics_users.event_purchase` (server_event_timestamp, user_id, platform, session_id)
      SELECT 
        event_timestamp - event_server_timestamp_offset AS server_event_timestamp,
        user_id,
        platform,
        (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id
      FROM `%s.events_intraday_*`
      WHERE
        _TABLE_SUFFIX = FORMAT_DATE('%%Y%%m%%d', CURRENT_DATE())
        AND user_id IS NOT NULL 
        AND event_name = 'purchase'
""", GA_dataset)

このコードは、project-id-devで実行されれば自動で開発GAソースを参照するため、誤って本番データソースに接続することを防ぎます。

まとめ

今回紹介した Dataform の環境分離テクニックは、以下の実現に直結します。

コスト最適化: 開発環境ではサンプリングを行い、クエリコストを大幅に削減できます。

堅牢な運用: workflow_settings.yaml による確実なプロジェクト分離と、@@project_id によるソースの誤参照防止で、本番環境を確実に守ります。

BigQuery環境を扱う上で、これらのテクニックは必須です。ぜひ活用してみてください。

次は、@block さんの記事です。お楽しみに!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?