📝
【Golang】GCSに上げられたCSVファイルからBigQueryにテーブルを作成する
実際にやってみようと記事を探し回ったところ、何箇所かつまづいたので記録を残す。
目標
GCSにCSVファイルがアップロードされたことを検知し、そのスキーマをパースしてBigQueryにテーブルを新しく生やす。
やること
- Cloud Functionsにデプロイするコードを用意する
- gcloudコマンドでデプロイ
コード
main.go
package gcstobq
import (
"cloud.google.com/go/bigquery"
"context"
"log"
"strconv"
"time"
)
type GCSEvent struct {
Bucket string `json:"bucket"`
Name string `json:"name"`
}
func GcsToBQ(ctx context.Context, e GCSEvent) error {
const (
dataset = "<BigQueryのDataset名>"
table = "<作成したいテーブル名>"
)
projectId := "<対象のBigQueryが存在するプロジェクトのID>"
client, err := bigquery.NewClient(ctx, projectId)
if err != nil {
log.Printf("client init error: %v", err)
return err
}
defer client.Close()
// create table from csv
gcsRef := bigquery.NewGCSReference("gs://" + e.Bucket + "/" + e.Name)
// ヘッダ行は無視
gcsRef.SkipLeadingRows = 1
// スキーマを自動取得
gcsRef.AutoDetect = true
loader := client.Dataset(dataset).Table(table).LoaderFrom(gcsRef)
// 対象のテーブルが存在しない場合のみ作成(上書きなどは行わない)
loader.WriteDisposition = bigquery.WriteEmpty
job, err := loader.Run(ctx)
if err != nil {
log.Printf("load run error: %v", err)
return err
}
status, err := job.Wait(ctx)
if err != nil {
log.Printf("wait error: %v", err)
return err
}
if status.Err() != nil {
log.Printf("job completed with error: %v", status.Err())
return err
}
return nil
}
go.mod
module example.com/gcstobq
go 1.16
require cloud.google.com/go/bigquery v1.25.0
以下略
デプロイ
gcloud functions deploy GcsToBQ --region=asia-northeast1 \
--runtime go116 \
--trigger-resource <Bucket名> \
--trigger-event google.storage.object.finalize
ハマったところ
エントリポイントの関数の引数
引数を無しでデプロイすると、ビルドは通過するが以下のようなエラー文とともにデプロイに失敗した。
This is likely due to a bug in the user code.
上記のサンプルコードのように引数を渡すと無事デプロイ成功した。
func GcsToBQ(ctx context.Context, e GCSEvent) error {
参照するCSVファイルのパスを適切に渡す
gs://
から始まるパスを渡す必要があった。
gcsRef := bigquery.NewGCSReference("gs://" + e.Bucket + "/" + e.Name)
モジュール名
example.com/<好きな名前>
の形にしないとビルド時に失敗した。
module example.com/gcstobq
AutoDetect
テーブルのスキーマ自動生成は列名が英語でないと文字化けする。
列名を英語にしておくか、スキーマ定義を自分であらかじめ定義しておく必要がある。
gcsRef.AutoDetect = true
参考にさせていただいた記事
Discussion