こんにちは。GMO NIKKOのharuです。
業務でBigQueryテーブルをCloudSQL(MySQL 8.0)テーブルに移送する必要があり、その時に色々と苦労したので、備忘録も兼ねて実装時に工夫した点/苦労した点をいくつかご紹介します。
背景
そもそもBigQuery->CloudSQL(RDB)というデータフローは一般的ではありません。ユーザがアプリケーション上で入力・操作などした情報を分析に用いるといった、CloudSQL->BigQueryというフローがメジャーで、技術記事もこのケースばかりがヒットします。CloudSQL->BigQueryは、Google Cloudが提供している連携クエリという機能を用いればすぐに実現できます。
一方業務では、ビックデータを集計処理した結果をユーザに提供したいといったケースであったため、BigQuery->CloudSQLというフローを採用することにしました。
データフロー図
工夫した点
メモリ量や分散処理を考えなくてよい実装にする
BigQueryのGCSエクスポート機能を用いることで、容量の大きいテーブルは自動的に分割されてエクスポートされます。後述するNULL置換処理の際、一時的にCloud Run Functionsのメモリ上にデータをのせることになりますが、ファイルが分割されているのでメモリのことを気にする必要はありません。
クエリエクスポートではなくテーブルエクスポートを用いる
BigQueryのGCSエクスポート機能は、クエリエクスポートとテーブルエクスポートがあります。前者はクエリ実行結果をエクスポートするため柔軟性が高いですが、クエリコストがかかります。後者はテーブル形式をそのまま全てエクスポートしてしまいますが、コストはかかりません。さらに、パーティションテーブルであれば、デコレータを用いて増分のみを指定することもでき、今回はこれを採用しました。
GCSのオブジェクトをCloudSQL import前に1つにまとめる
データを処理する際は上で述べたとおり分割されているほうが都合が良いのですが、CloudSQL(MySQL)のcsvインポートは直列インポートしかサポートしていない(MySQL dump形式はサポートしているのですが。。)ので、1つにまとめたほうが効率が良いです。そのため、GCSのcomposeオペレーションを用いて分割されたオブジェクトを1つにまとめました。 (ここでは詳細は述べませんが、GCSのcomposeオペレーションは最大で32のオブジェクトを1つにまとめる機能のため、分割数が32を超える場合はloop処理をする必要があります。)
苦労した点
NULLの処理
BigQueryからテーブルエクスポートされたcsvファイルは、NULL値を引用符なしの空文字に変換します。それをそのままCloudSQLにインポートすると、カラム型のデフォルト値?(INTEGERなら0, STRINGなら空文字)のようなものに置き換わってしまいます。CloudSQLでは引用符なしのNULLという文字列がNULLとして挿入されるので、csvファイルの該当文字列を置換する作業を行いました。(もともと文字列NULLがデータとしてある場合は、引用符をつければよいです。)
さいごに
今回はBigQueryからCloudSQL(MySQL)へデータをインポートする際の工夫した点/苦労した点を紹介しました。みなさんの助けになれば幸いです。それではまたの機会に。