📝

小ネタ:BigQueryからGCSに1ファイルでデータ出力する

2024/11/11に公開

はじめに

BigQueryはMPP(Massive Parallel Processing)のアーキテクチャで普通にGCSに出力すると、多数のファイルに分かれて出力されてしまいます。
GCSに 1 ファイルに出力したいけどできなかった経験をされた人は多そうですが、対処法について情報が少なくあまり知られてなさそうなので記事にしてみました。

1GB以下の場合

export data options でGCSに小さいデータを出力するとき、order by を使うと 1 ファイルに出力できます。limitdistinct を使ってもできます。このように、クエリ結果をソートしたりしてGCSに書き込む処理を 1 worker で実行するように制御できれば 1 ファイルで出力できるようです (参考記事)。

export data options (
  uri = 'gs://your-bucket/foo/bar/exported_file_*.csv',
  format = 'csv',
  field_delimiter = ',',
  header = true,
  overwrite = true
) as
select *
from your_dataset.your_table
order by 1 -- Force all data to be loaded into one worker/file using `order by` (if <=1GB)

なお、大きいデータの場合は 1 ファイルにならなくてもファイル数を少なくできるので、なるべくファイル数を抑えたい場合にもこの方法が有効です。

1GBを超える場合

データ量が大きいと直接 1 ファイルに出力できないので、複数ファイルに出力してから 1 ファイルにまとめるアプローチを取ります。
ちなみに、この場合 header=false にしないとファイル数分の header を結合してしまう点に注意です。

Command Line

gsutil compose で31ファイルまでは結合できますが、それより多い場合の方法は下記で紹介されています。

https://nakano-tomofumi.hatenablog.com/entry/2021/02/16/190626

なお、gsutil が not recommended になったので、代わりに gcloud storage objects compose を使いましょう。

Programming Language

Google Cloud open tutorials のリポジトリで accumulator パターン を応用したPythonの実装例が紹介されています。

https://github.com/GoogleCloudPlatform/community/blob/master/archived/cloud-storage-infinite-compose/index.md

デモンストレーション目的であり production-ready でないと記載あり、オブジェクト削除が並列処理になっている辺りが怪しいので、single-thread にするか、並列処理の終了を担保する仕組みの追加が必要そうです。

RAKSUL Data Analytics

Discussion