· ハルボウヤ · dataflow · 11 min read

GCPでのデータ取り込みを、どういう構造にしているか

生データ層・中間層・提供層の3層構成、取り込みの3経路、冪等性の担保、コストと失敗の監視まで。BigQueryを中心にしたデータ取り込みの型を整理する。

データ取り込みの3層構成を示した図。生データ層、中間層、提供層が縦に並び、それぞれの役割が添えられている

複数のサービスからデータを集めてくると、取り込み方がサービスごとにバラバラになる。数が増えたところで破綻し、誰も全体を把握できなくなる。

そうならないよう、取り込みの構造を先に決めて、新しい連携もその型に乗せる。ここでは実際に使っている構成を、固有の設定値を伏せた形で整理する。

3層に分ける

BigQuery のデータセットを役割ごとに3つに分ける。

外部サービス / ファイル

[ raw ]   生データ層
          加工しない。届いたまま置く

[ stg ]   中間層
          型の統一、名寄せ、重複排除

[ mart ]  提供層
          BIツールや連携先が直接参照する

分ける理由は、数値がおかしいときに切り分けができること。

症状見る場所分かること
数字が出ないrawそもそも届いていないのか
数字が変stg加工で壊れたのか
表示が変mart定義の問題か、BI側の問題か

層を分けていないと、この切り分けに毎回時間を取られる。3つのデータセットを作るだけで済む話なので、最初にやっておく。

raw は絶対に加工しない。ここを「ついでに整形」し始めると、届いたデータの原形が失われ、比較対象がなくなる。

取り込みの3経路

外部からデータが入ってくる経路は、実質3種類に収まる。

経路1:GCSからのバッチロード

ファイルを GCS に置き、BigQuery に読み込む。CSV や JSON で出力されるデータはこれ。

利点は、失敗してもやり直せること。 読み込みに失敗しても、ファイルは GCS に残っている。提供元に再送を依頼せずに読み直せる。

バケットは用途ごとに分け、ライフサイクルルールを最初に設定する

30日経過  → Nearline へ移行
90日経過  → 削除

ファイルが溜まり続けると、ストレージ費用が静かに増える。後から棚卸しするより、最初にルールを置くほうが安い。

経路2:外部サービスからの直接書き込み

連携先のサービスが、こちらの BigQuery に直接書き込む。相手にサービスアカウントを渡して権限を付ける形。

権限はデータセット単位で付ける。プロジェクト全体に編集者を渡すと、連携と無関係なデータセットまで書き換えられる状態になる。

書き込み先は raw の中でも専用のデータセットに隔離する。外部から書かれる領域と、社内で作る領域を混ぜない。

経路3:スケジュールドクエリ

BigQuery 内で完結する定期処理。他システムから来たデータを整形して次の層に渡す。

素朴に組むと依存関係が管理できなくなる。変換処理は後述の Dataform に寄せ、スケジュールドクエリは単発の用途に留める

冪等性を最初に決める

同じ処理を2回実行しても、結果が同じになること。 これが担保されていないと、再実行が怖くてできなくなる。

取り込みで一番多い事故が「再実行したら件数が2倍になった」。

対処は、日付でパーティションを切り、対象日のパーティションだけを入れ替える

-- 対象日だけを置き換える。何度実行しても結果は同じ
CREATE OR REPLACE TABLE `プロジェクト.raw.テーブル$20260911`
AS
SELECT ...
FROM  外部ソース
WHERE event_date = '2026-09-11';

全件を書き直さないのでコストも抑えられる。キーで突き合わせる必要があるなら MERGE を使うが、まずはパーティション単位の入れ替えで足りることが多い。

Append は避ける。速いが、再実行のたびに重複する。遅れて届いたデータを取り直す運用と両立しない。

変換は Dataform に寄せる

stg と mart の変換は Dataform にまとめる。SQL をファイルとして管理し、依存関係から実行順を自動で決める仕組み。

得られるものは3つ。

依存関係が明示される。 どのテーブルがどれを参照しているかが定義から分かる。テーブルを直す前に、影響範囲を確認できる。

アサーションが書ける。 「このカラムは NULL であってはならない」「このキーは重複してはならない」を定義に書いておくと、条件を満たさないときに処理が止まる。壊れたデータが下流に流れない。

Git で履歴が残る。 誰がいつ何を変えたかが追える。定義の変更と数値の変化を突き合わせられる。

運用上の注意点として、開発ワークスペースは Git から手動で取り込まないと最新にならない。ブラウザ上で編集していると、リポジトリ側の変更が反映されていない状態に気づきにくい。作業前に取り込む習慣にしておく。

命名規則

名前で「どこにあるか」「何者か」が分かる状態にする。

対象規則
データセット層の名前をそのまま使うraw / stg / mart
raw のテーブル提供元 + 内容<提供元>_<内容>
stg のテーブル内容 + 粒度<内容>_daily
mart のテーブル用途が分かる名前<レポート名>_summary
日付カラム全テーブルで同じ名前に揃えるevent_date

日付カラムの名前を揃えるのが地味に効く。テーブルごとに date dt event_date が混在していると、結合のたびに定義を確認することになる。

監視は BigQuery 自身で足りる

INFORMATION_SCHEMA を使えば、ジョブの実行履歴とスキャン量を SQL で取れる。

-- 直近7日の、処理量が多いジョブと失敗したジョブ
SELECT
  DATE(creation_time, 'Asia/Tokyo')                 AS run_date,
  job_id,
  user_email,
  ROUND(total_bytes_processed / POW(1024, 3), 2)    AS scanned_gb,
  TIMESTAMP_DIFF(end_time, start_time, SECOND)      AS duration_sec,
  error_result.reason                               AS error_reason
FROM `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND job_type = 'QUERY'
  AND (error_result IS NOT NULL OR total_bytes_processed > 50 * POW(1024, 3))
ORDER BY run_date DESC, scanned_gb DESC;

これで次の2つが同時に見える。

  • 失敗したジョブerror_reason が入っているもの)
  • 重いジョブ(スキャン量が閾値を超えたもの)

コストが跳ねたとき、原因のクエリを特定できる。費用の請求書を見てから調べ始めると、その月はもう終わっている。

あわせて、層ごとに件数の日次チェックを置く。raw の件数が0なら取り込み失敗、raw はあるのに mart が0なら変換の失敗と、層で切り分けられる。

権限

サービスアカウントは用途ごとに分ける。1つを使い回すと、事故のときに影響範囲が特定できない。

用途権限の範囲
外部サービスからの書き込みraw の該当データセットのみ・編集者
変換処理raw 閲覧者 + stg / mart 編集者
BIツールからの参照mart のみ・閲覧者

BIツールに raw を見せないのが要点。加工前のデータを誰でも参照できる状態にすると、そこから直接レポートが作られ始める。定義がバラバラなレポートが増える原因になる。

この構成にしている理由

決めごと効いてくる場面
3層に分ける数値がおかしいときの切り分け
raw は加工しない比較対象が残る
GCS を挟む取り込みの再実行
パーティション単位の上書き再実行しても重複しない
変換を Dataform に寄せる影響範囲の確認と履歴
命名規則を揃える引き継ぎ
INFORMATION_SCHEMA で監視コストと失敗の早期発見
権限を用途別に分ける事故の影響範囲の限定

どれも作るときは手間に見えるが、効いてくるのは半年後、担当者が代わったとき。データ基盤は、作った本人がいなくなってからのほうが長く使われる。

Share:
Back to Blog

Related Posts

View All Posts »
AIを会社に導入していく手順

AIを会社に導入していく手順

ツールを配るだけでは定着しない。中小企業と大企業で何が違うのかを分けて、導入から定着までの手順を整理する。