BigQuery API操作(データ参照・テーブルコピー・GCSへのエクスポート)をGoクライアントライブラリ経由で試してみた

2020.12.05

当エントリは、『クラスメソッド BigQuery Advent Calendar 2020』5日目のエントリです。
本アドベントカレンダーでは、12月01日〜12月25日までの25日間、弊社DA(データアナリィクス)事業本部のメンバーがBigQueryに関連するブログを公開していきます。

今回は、BigQueryのクライアントライブラリ(Go言語)経由でAPI操作を試してみたので、まとめていきます。

試したこと

ローカルからBigQueryに対して、下記のAPI操作をGoクライアントライブラリ経由で試してみました。

  • テーブルデータの参照
  • テーブルコピー
  • GCS(Google Cloud Storage)へのエクスポート

事前準備

今回はGoのインストール方法などについては割愛させていただきます。
下記のリンクなどを参考にして簡単にインストールすることができます。
※今回使用したgoのバージョンは、1.15.5です。

クライアントライブラリのインストール

Goがインストール済みであれば、ターミナル等から下記を実行してBigQueryのクライアントライブラリを取得できます。

go get -u cloud.google.com/go/bigquery

認証用JSONファイルの作成

クライアントライブラリを実行するために、サービスアカウントを作成しました。今回は
公式ドキュメントの手順を参考に、下記のようなJSONファイルをダウンロードしました。

※今回はJSONファイルを環境変数に設定するのではなく、コード上でJSONファイルパスを直接指定し、クライアント生成時に認証するようにしています。

{
  "type": "service_account",
  "project_id": "ohama-nagamasa",
  "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "private_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "client_email": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "client_id": "XXXXXXXXXXXXXXXXXXXX",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

サンプルデータ

下記のツールを使用して、サンプルデータを作成しました。

作成したサンプルデータです。全てランダムな値です。

name,age,email
ミノワ コウヘイ,62,dMqTEtY@sample.jp
エチ ヒロユキ,21,OnwHgB@example.net
モガミ ハルヨ,19,afZmJPFeXL@test.jp
イナムラ ヒロ,30,CmenAM@test.jp
コヤナギ ミワ,38,W94f1P@example.jp
ムラヤマ ヒロカズ,14,YXZ3ISWB7s@example.net
ナルセ チアキ,53,YOf99aY@sample.org
シバサキ トキオ,27,uPZjnO@sample.co.jp
クスダ ヒロトシ,36,laTjg@test.co.jp
サイトウ カホ,47,cXUwYHABnJ@sample.co.jp

事前に上記のデータをBigQuery上で読み込んでおきました。

BigQueryのデータ読み込む方法については、下記ブログ等をご参照ください。

試してみた

データ参照

まずはデータ参照です。
下記のコードを使用して、テーブルデータを参照しました。
select文でデータを取得し出力している簡単なコードです。

package main

import (
    bq "cloud.google.com/go/bigquery"
    "google.golang.org/api/iterator"
    "google.golang.org/api/option"
    "context"
    "fmt"
)

func main() {
    
    ctx := context.Background()
    
    projectID := "ohama-nagamasa"
    
    // 認証用JSONファイルのパスを指定
    key := "/XXXXX/XXXXX/ohama-nagamasa-XXXXX.json"
    
    // 認証用JSONファイルを設定し、BigQuery用のclientを生成
    client, err := bq.NewClient(ctx, projectID, option.WithServiceAccountFile(key))
    
    if err != nil {
        fmt.Println("Failed to create client:%v", err)
    }
    defer client.Close()
    
    query(ctx, client)
}

func query(ctx context.Context, client *bq.Client) {
 
    q := "select name, age, email from `ohama-nagamasa.sample_demo.user` order by age"

    // SQLクエリを実行
    it, err := client.Query(q).Read(ctx)

    if err != nil {
        fmt.Println("Failed to Read Query:%v", err)
    }
    
    for {
    
        var values []bq.Value
        
        err := it.Next(&values)
        
        if err == iterator.Done {
            break
        }
        
        if err != nil {
            fmt.Println("Failed to Iterate Query:%v", err)
        }
        
        fmt.Println(values)
    }
}

実行結果です、データを参照できました〜。

$ go run query.go
[ムラヤマ ヒロカズ 14 YXZ3ISWB7s@example.net]
[モガミ ハルヨ 19 afZmJPFeXL@test.jp]
[エチ ヒロユキ 21 OnwHgB@example.net]
[シバサキ トキオ 27 uPZjnO@sample.co.jp]
[イナムラ ヒロ 30 CmenAM@test.jp]
[クスダ ヒロトシ 36 laTjg@test.co.jp]
[コヤナギ ミワ 38 W94f1P@example.jp]
[サイトウ カホ 47 cXUwYHABnJ@sample.co.jp]
[ナルセ チアキ 53 YOf99aY@sample.org]
[ミノワ コウヘイ 62 dMqTEtY@sample.jp]

テーブルコピー

次に下記のコードでテーブルのコピーを試してみました。
今回は「user」テーブルをコピーして「user_bkup」テーブルを作成しました。

package main

import (
        bq "cloud.google.com/go/bigquery"
        "google.golang.org/api/option"
        "context"
        "fmt"
)

func main() {
    
    ctx := context.Background()
    
    projectID := "ohama-nagamasa"
    
    // 認証用JSONファイルのパスを指定
    key := "/XXXXX/XXXXX/ohama-nagamasa-XXXXX.json"
    
    // 認証用JSONファイルを設定し、BigQuery用のclientを生成
    client, err := bq.NewClient(ctx, projectID, option.WithServiceAccountFile(key))
    
    if err != nil {
        fmt.Println("Failed to create client:%v", err)
    }
    
    defer client.Close()
    
    copyTable(ctx, client)
}

func copyTable(ctx context.Context, client *bq.Client) {
        
        dataset := client.Dataset("sample_demo") // データセットIDを指定
        
        // コピー元の「user」テーブルから、「user_bkup」テーブルを生成するよう設定
        copier := dataset.Table("user_bkup").CopierFrom(dataset.Table("user"))
        copier.WriteDisposition = bq.WriteTruncate
        
        job, err := copier.Run(ctx)
        if err != nil {
            fmt.Println("Failed to copy job:%v", err)
        }
        
        // ジョブが終了するまで待つ
        status, err := job.Wait(ctx)
        if err != nil {
            fmt.Println("Failed to copy job:%v", err)
        }
        
        if err := status.Err(); err != nil {
            fmt.Println("Failed to copy job:%v", err)
        }
        
        fmt.Println("copy fin.")
}

Google Cloud Console上でコピーしたテーブルの確認ができました。

GCS(Google Cloud Storage)へのエクスポート

最後にGCSへのエクスポートを試してみます。

事前に適切な権限でGCS上にextract-demoというバケットを作成しました。
今回はextract-demoバケット直下に、「user」テーブルのデータをエクスポートしました。

package main;

import (
        bq "cloud.google.com/go/bigquery"
        "google.golang.org/api/option"
        "context"
        "fmt"
)

func main() {
    
    ctx := context.Background()
    
    projectID := "ohama-nagamasa"
    
    // 認証用JSONファイルのパスを指定
    key := "/XXXXX/XXXXX/ohama-nagamasa-XXXXX.json"
    
    // 認証用JSONファイルを設定し、BigQuery用のclientを生成
    client, err := bq.NewClient(ctx, projectID, option.WithServiceAccountFile(key))
    
    if err != nil {
        fmt.Println("Failed to create client:%v", err)
    }
    defer client.Close()
    
    exportTable(ctx, client)
}

func exportTable(ctx context.Context, client *bq.Client) {
        
        projectID := "ohama-nagamasa"
        datasetID := "sample_demo"
        table := "user"
        
        gcsRef := bq.NewGCSReference("gs://extract-demo/user.csv")
        
        // 指定したGCSのURIへデータをエクスポートするよう設定
        extractor := client.DatasetInProject(projectID, datasetID).Table(table).ExtractorTo(gcsRef)
        extractor.DisableHeader = true
        
        job, err := extractor.Run(ctx)
        
        if err != nil {
            fmt.Println("Failed to extract job:%v", err)
        }
        
        // ジョブが終了するまで待つ
        status, err := job.Wait(ctx)
        if err != nil {
            fmt.Println("Failed to extract job:%v", err)
        }
        if err := status.Err(); err != nil {
            fmt.Println("Failed to extract job:%v", err)
        }
        
        fmt.Println("extract fin.")
}

こちらもGoogle Cloud Consoleでエクスポートされていることを確認できました〜。

(オプションなどはあまり試せてないですが) 3つの操作をとくにハマることなく簡単に試せました!

おわりに

今回はGoクライアントライブラリを使用して、よく使いそうな3つの操作を試してみました。
ライブラリが非常に便利だったので、思ってたより簡単にAPI操作ができて良かったです。BigQueryで開発する際のイメージも湧きました!
他の言語のクライアントライブラリ、他のAPI操作やオプションなども引き続き確認していこうと思います。

『クラスメソッド BigQuery Advent Calendar 2020』 6日目は、みかみさんです。お楽しみに!
以上、DA(データアナリティクス)事業本部のナガマサでした〜!

参考