🪣

別リージョンのGCSからBigQueryに定期的に安くデータを移す方法

はじめに

USリージョンにあるGCSバケットのデータを東京のBigQueryのデータセットに定期的に移す必要があったので、そのときに採用した方法を書いてみます。

結論

2つのスケジュールドクエリを使用して、データの移行を行いました。

元データ(US)からフィルタ後のデータ(東京)へ矢印1が向かい、フィルタ後のデータ(東京)からBigQuery(東京)に矢印2が向かう
  1. USのバケットのデータを外部テーブルにして、データをフィルタリングしつつ、東京のGCSバケットにエクスポート
  2. 東京のGCSバケットにエクスポートされたデータを、東京のBigQueryデータセットにインポート

1. USのバケット → 東京のバケット

まず、最もお金がかかるのがリージョン間のデータ転送料金です。できるだけ、データ量を減らしてから別リージョンにデータを移すことを考えます。

今回は元のデータ全てが必要なわけではなかったので、1つ目のスケジュールドクエリでデータをフィルタリングしました。 僕の場合はこれでデータを10分の1程度にしてから東京のバケットにエクスポートしました。

BigQueryでは、外部テーブルを作成することで、GCSのデータを参照できます。これを利用して、フィルタリング結果を東京のバケットにエクスポートしました。

-- 外部テーブルの作成(Avroファイルを指定)
CREATE OR REPLACE EXTERNAL TABLE dataset_in_us.external_avro_table
OPTIONS (
  format = 'AVRO',
  uris = ['gs://bucket-in-us/some-file.avro']
);

-- フィルタリング結果をParquet形式でエクスポート
EXPORT DATA OPTIONS(
  uri='gs://bucket-in-tokyo/exported-data-*.parquet',
  format='PARQUET'
)
AS
SELECT 
  *
FROM dataset_in_us.external_avro_table
WHERE
  some_column = 'some_value'; -- フィルタリング条件
;

parquet形式でエクスポートすることで、jsonlやCSVよりもデータ量を削減できます。

エクスポートのオプションの詳細は公式ドキュメントを参照してください。

ポイント

大量のデータをエクスポートする際は、ワイルドカードの*をURIに含めるのがミソです。具体的には1GBを超える場合には、*を使って複数のファイルに分割してエクスポートしなければいけません

2. 東京のバケット → BigQuery

こちらは比較的単純で、東京のバケットにエクスポートされたデータをBigQueryにインポートするだけです。

フォーマットや圧縮形式はエクスポート時と同じものを指定します。

LOAD DATA INTO dataset_in_tokyo.my_table
  FROM FILES (
    uris=['gs://bucket-in-tokyo/exported-data-*.parquet'], -- ①でエクスポートされたデータのURI
    format='PARQUET'
  );

ポイント

もし、データセットに入れて実体化させる必要がない場合は、先ほどと同じように外部テーブルを作成して参照するだけでもいいかもしれません。

まとめ

リージョン間のデータ移行は、転送料金を考えるとできるだけデータ量を減らすことが重要です。転送前にできるだけフィルタリングしたり、parquet形式でエクスポートすることでデータ量を削減しましょう。 また、ちゃんとやるならdataformを使ってパイプライン化した方が安全ですね。