rubyでgoogleのAPIを使うならgoogle-api-ruby-clientや他のラッパーしたgemを使用することがあると思いますが、google-api-ruby-client でBigQueryを扱うのに結構苦労したので忘れない為のメモになります。
今回のメモはbatchでbigqueryを叩く前提になります。
なのでフロント側でユーザー認証させたい場合は認証の仕方が変わりますのでご注意ください。
先に謝っておきます。当方rubyはまだ初心者なのでツッコミ歓迎です。
環境
- centos6.7
事前準備に必要なもの
- Ruby 2.3.1p112
- Rails 4.2.6
- 今回は特にrailsなんちゃらはでてきません
-
Google Cloud Platformで課金設定まで済ましていること
- はじめの一歩が踏み出せない人のためのBigQuery入門を参考にしてデータセットの作成まで完了しておいてください。
- 認証情報でサービス アカウント クライアントを作成して認証情報のjsonを作成していること
認証情報のjsonは下記のようなフォーマットのjsonになります。
{
"type": "service_account",
"project_id": "xxxxxxxxxx",
"private_key_id": "xxxxxxxxxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----xxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n",
"client_email": "123456789-xxxxxx@developer.gserviceaccount.com",
"client_id": "123456789-xxxxxxxxxx.apps.googleusercontent.com",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/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/123456789-xxxxxxxxx%40developer.gserviceaccount.com"
}
参考にしたサイト
- Google Cloud Platform API Reference BigQuery
- RubyでBigQuery始めました
- bq コマンドライン ツール クイックスタート
- bigquery-client という gem を作った
- abronte/BigQuery
最近google-api-ruby-clientが大幅なアップデートがされています
すみません。最近っていつなんだよ?ってところまでは調べていません。
参考: google-api-ruby-clientが非互換なアップデートされた
なのでbigquery ruby とかでググって試してみても、メソッドのインターフェースが大分違っているので注意しましょう。
この関係でabronte/BigQueryなどはgemのバージョン指定しないと動かないので注意が必要です。
gem 'google-api-client', '~> 0.8.6'
abronte/BigQueryを使う手もあったですが、最近Google関連のものが頻繁にアップデートされている印象を受けたので
本家のgoogle-api-clientを使うことにしました。
ちゃんと試していないですが、BigQueryをrubyで使いたいという要件ならおそらく
を使ったほうが楽に扱えると思います。
exampleとかググってもアップデート後の使い方はほとんどありません
なのでruby初心者だけども、Gemの中身見まくって頑張りました。
BigQuery UIで動作確認をするときの注意事項
- データセットの作成
- データセットにテーブルを作成する
まではUIで確認できますが、テーブルにデータ投入後のデータの確認は人によって見れない場合があります。
僕はコレでAPIレスポンスが200なのにBigQuery UI でデータが入っていない現象(実際はbqで見れば入っていた)で半日ハマりました。。
データ投入の確認は BigQuery CommandLine Toolを使って確認することを強くおすすめします。
bq query "SELECT count(*) FROM dataset_id.table_id"
google-api-clientの構成と仕組み
ちゃんと調べていないのですが、google-api-clientのリポジトリを調べてもservice単位でのソースコードは検索できません。
なぜならばサービス単位のAPIはgenerateされて作られてるみたいです。
通常のGemの構成ならば lib/
以下にファイルがあるはずですが、google-api-clientの場合は generated/
以下にAPIサービス関連のロジックが配置されています。
lib/
以下は認証系のメソッドとAPIコール系のメソッドとかしかない感じです(厳密には調べていません)
以下tree
vendor/bundle/ruby/2.3.0/gems/google-api-client-0.9.6
├── bin
├── generated
│ └── google
│ └── apis #一部APIは省略
│ ├── analytics_v3
│ ├── bigquery_v2
│ ├── youtube_partner_v1
│ ├── youtube_v3
│ └── youtubereporting_v1
├── lib
│ └── google
│ ├── api_client
│ │ └── auth
│ │ └── storages
│ └── apis
│ ├── core
│ └── generator
│ └── templates
├── rakelib
├── samples
│ ├── cli
│ │ └── lib
│ │ └── samples
│ └── web
│ └── views
└── third_party
3 [error opening dir]
google-api-client-0.9.6/generated/google/apis/bigquery_v2.rb
Google APIのscopeの定義が記載されています。
google-api-client-0.9.6/generated/google/apis/bigquery_v2/service.rb
API実行のインターフェースメソッドがあります。
今回はservice.rbの中のメソッド
- get_table
- BigQueryデータセットの中にあるテーブル情報を取得
- insert_table
- BigQueryデータセットにテーブルを作成する
- delete_table
- BigQueryデータセットの中にあるテーブルを削除する
- insert_all_table_data
- BigQueryデータセットの中にあるテーブルにstreamingデータ挿入をする
の使い方のメモです
(select系は追って記載します)
何はともあれGemをインストールする
Gemfileに記載しましょ
gem 'google-api-client'
bundle install
bundle install
認証をする
batch実行(rails runner)を想定した認証になります。
scopeは状況に応じて適切な設定を行ってください。
require 'googleauth'
require 'googleauth/stores/file_token_store'
require 'google/apis/bigquery_v2'
module Tasks
module Hoge
GOOGLE_CRED_JSON_PATH = File.join(File.expand_path(File.dirname(__FILE__)), "../../config/tasks/google-auth-cred.json")
ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
BigQuery = Google::Apis::BigqueryV2
def self.init
@bigquery = BigQuery::BigqueryService.new
@bigquery.authorization = ServiceAccountCredentials.make_creds(
json_key_io: File.open(GOOGLE_CRED_JSON_PATH),
scope: [
self::BigQuery::AUTH_BIGQUERY,
self::BigQuery::AUTH_CLOUD_PLATFORM,
self::BigQuery::AUTH_DEVSTORAGE_FULL_CONTROL,
self::BigQuery::AUTH_BIGQUERY_INSERTDATA
]
)
@bigquery
end
end
end
get_table
BigQueryデータセットの中にあるテーブル情報を取得します。
動作確認をするために最初に何かしらのサンプルテーブルを作成しておいてください。
先ほどの認証部分を除外した内容です。
table_idはtable名を指定してください。
module Tasks
module Hoge
PROJECT_ID = "sample-bigquery"
DATASET_ID = "sample-dataset"
def self.execute
# データテーブル情報を取得する
@bigquery.get_table(self::PROJECT_ID, self::DATASET_ID, "teble_id")
end
end
end
insert_table
BigQueryのデータセットにテーブルを作成する
schemaの定義一覧などはBigQueryUI等をみれば、どういう定義があるかわかると思います。
module Tasks
module Hoge
PROJECT_ID = "sample-bigquery"
DATASET_ID = "sample-dataset"
def self.execute
schema = [
{ name: "id", type: "INTEGER", mode: 'required', description: "uniq id"},
{ name: "path", type: "STRING", description: "testing string filed"},
{ name: "pv", type: "INTEGER", description: "testing string filed"}
]
table = BigQuery::Table.new(
table_reference: { project_id: self::PROJECT_ID, dataset_id: self::DATASET_ID, table_id: "table_id" },
schema: { fields: schema }
)
begin
@bigquery.insert_table(
self::PROJECT_ID,
self::DATASET_ID,
table
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
end
end
delete_table
BigQueryデータセットの中にあるテーブルを削除する
module Tasks
module Hoge
PROJECT_ID = "sample-bigquery"
DATASET_ID = "sample-dataset"
def self.execute
begin
@bigquery.delete_table(
self::PROJECT_ID,
self::DATASET_ID,
"table_id"
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
end
end
insert_all_table_data
BigQueryデータセットの中にあるテーブルにstreamingでデータ挿入をします。
streamingデータの場合は容量単位で課金されますので、ご注意ください。
module Tasks
module Hoge
PROJECT_ID = "sample-bigquery"
DATASET_ID = "sample-dataset"
def self.execute
rows = [
{
:insertId => "hoge",
:json => { id: 1, path: "12345", pv: 99999 }
},
{
:insertId => "fuga",
:json => { id: 2, path: "67890", pv: 99999 }
},
]
insert_all_table_data_request = Google::Apis::BigqueryV2::InsertAllTableDataRequest.new({
:rows => rows
})
begin
@bigquery.insert_all_table_data(
self::PROJECT_ID,
self::DATASET_ID,
"table_id",
insert_all_table_data_request
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
end
end
認証までまとめるとこんな感じ
module Tasks
module Hoge
GOOGLE_CRED_JSON_PATH = File.join(File.expand_path(File.dirname(__FILE__)), "../../config/tasks/google-auth-cred.json")
ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
BigQuery = Google::Apis::BigqueryV2
def self.init
@bigquery = BigQuery::BigqueryService.new
@bigquery.authorization = ServiceAccountCredentials.make_creds(
json_key_io: File.open(GOOGLE_CRED_JSON_PATH),
scope: [
self::BigQuery::AUTH_BIGQUERY,
self::BigQuery::AUTH_CLOUD_PLATFORM,
self::BigQuery::AUTH_DEVSTORAGE_FULL_CONTROL,
self::BigQuery::AUTH_BIGQUERY_INSERTDATA
]
)
@bigquery
end
#table情報を参照
def self.get_table
@bigquery.get_table(self::PROJECT_ID, self::DATASET_ID, "teble_id")
end
#テーブルの作成
def self.create_table
schema = [
{ name: "id", type: "INTEGER", mode: 'required', description: "uniq id"},
{ name: "path", type: "STRING", description: "testing string filed"},
{ name: "pv", type: "INTEGER", description: "testing string filed"}
]
table = BigQuery::Table.new(
table_reference: { project_id: self::PROJECT_ID, dataset_id: self::DATASET_ID, table_id: "table_id" },
schema: { fields: schema }
)
begin
@bigquery.insert_table(
self::PROJECT_ID,
self::DATASET_ID,
table
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
# テーブルの削除
def self.delete_table
begin
@bigquery.delete_table(
self::PROJECT_ID,
self::DATASET_ID,
"table_id"
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
# streaming insert
def self.insert_all_table_data
rows = [
{
:insertId => "hoge",
:json => { id: 1, path: "12345", pv: 99999 }
},
{
:insertId => "fuga",
:json => { id: 2, path: "67890", pv: 99999 }
},
]
insert_all_table_data_request = Google::Apis::BigqueryV2::InsertAllTableDataRequest.new({
:rows => rows
})
begin
@bigquery.insert_all_table_data(
self::PROJECT_ID,
self::DATASET_ID,
"table_id",
insert_all_table_data_request
)
rescue Google::Apis::ClientError => ex
p ex.message
end
end
end
最後に
結局シンプルなのですが、ここまでたどり着くまでに苦労した・・・・・
なruby初心者のつぶやきです・・・・