BigQuery の API を Ruby から扱う bigquery-client という gem を作りました。
もともと BigQuery の gem といえば abronte/BigQuery があったんですが、個人的に欲しい機能がなかったのと、当時所属していたプロジェクトでは BigQuery を多用していて、もっと汎用的なものが必要だったので新しく作ることにしました。
インストール
% gem install bigquery-client
基本的な使い方
require "bigquery-client"
client = BigQuery::Client.new(
project: "your-project-42",
dataset: "your_dataset",
email: "1234567890@developer.gserviceaccount.com",
private_key_path: "/path/to/keyfile.p12",
private_key_passphrase: "notasecret",
auth_method: "private_key"
)
client.sql "SELECT * FROM publicdata:samples.wikipedia LIMIT 10"
INSERT
BigQuery::Client#insert
を使うとレコードの INSERT ができます。内部的には Streaming Insert (insertAll) を使用しています。
client.insert("table_name", nickname: "john", age: 42)
# 配列で渡せば複数行をまとめて insert できる
rows = [
{ nickname: "foo", age: 43 },
{ nickname: "bar", age: 44 }
]
client.insert("table_name", rows)
CREATE TABLE
テーブルを作成します。
schema = [
{ name: "foo", type: "timestamp" },
{ name: "bar", type: "string" }
]
client.create_table("new_table_name", schema)
SELECT
手軽に SELECT したい場合は BigQuery::Client#sql
を使うのが良いです。
client.sql "SELECT * FROM dataset_name.table_name LIMIT 100"
BigQuery には INTEGER, STRING, BOOLEAN, FLOAT, TIMESTAMP といったデータ型がありますが、BigQuery::Client#sql
はこれらのカラムをパースして、ハッシュの配列に詰めて結果を返します。
client.sql "SELECT born_alive_alive,is_male,weight_pounds FROM publicdata:samples.natality LIMIT 2"
#=> [{"born_alive_alive"=>0, "is_male"=>true, "weight_pounds"=>8.437090766739999}, {"born_alive_alive"=>2, "is_male"=>true, "weight_pounds"=>6.8122838958}]
tables
データセット内にあるテーブルの一覧を返します。
client.tables
#=> ["your_table", "your_table2", "your_table3"]
fetch_schema
テーブル名を指定してスキーマを取得します。
client.fetch_schema("table_name")
#=> [{"name"=>"nickname", "type"=>"STRING"}, {"name"=>"age", "type"=>"INTEGER"}]
DELETE
テーブル名を指定してテーブルを削除します。
client.delete_table('table_name')
Datasets API
bigquery-client はデータセットを扱う API もサポートしています。データセットを扱うだけならば:dataset
を指定する必要はありません。
# `:dataset`は省いても OK
client = BigQuery::Client.new(
project: "your-project-42",
email: "1234567890@developer.gserviceaccount.com",
private_key_path: "/path/to/keyfile.p12",
private_key_passphrase: "notasecret",
auth_method: "private_key"
)
# データセットの一覧を取得
client.datasets
#=> ["your_dataset", "your_dataset2"]
# データセットを作成
client.create_dataset('dataset_name')
# データセットを削除
client.delete_dataset('dataset_name')
Projects API
プロジェクトを扱う API もサポートしています。プロジェクトを扱うだけならば:dataset
や:project
を指定する必要はありません。
# `:dataset`と`:project`は省いても OK
client = BigQuery::Client.new(
email: "1234567890@developer.gserviceaccount.com",
private_key_path: "/path/to/keyfile.p12",
private_key_passphrase: "notasecret",
auth_method: "private_key"
)
# プロジェクトの一覧を取得
client.projects
#=> ["your_project"]
豆知識
bigquery-client は手軽に扱えることを重視して開発しました。例えば BigQuery::Client#datasets
は API のレスポンスに含まれる、おそらくは普通の用途では使用しないであろう情報を落として、データセット名だけをただの文字列の配列として返すようになっています。
client.datasets #=> ["your_dataset", "your_dataset2"]
ですが、例えば bigquery-client を使用した gem を作る場合など、突っ込んだ用途で使用する場合には、BigQuery::Client#datasets
が捨ててしまう一部の情報が必要になる場合もあるかと思います。そういった用途のために、bigquery-clietnt には API を叩いて素のレスポンスを返すだけのメソッドを別途用意してあります。これらのメソッドも private になってはおらず、利用できます。
# 内部的には list_datasets を使用
def datasets
list_datasets['datasets'].map {|dataset| dataset['datasetReference']['datasetId'] }
end
# こっちも public メソッド
def list_datasets
access_api(
api_method: bigquery.datasets.list
)
end
お願い: 足りない機能は Pull Request ください
BigQuery の API にはエンドポイントが数多くあり、すべてのエンドポイントをサポートしたうえで各メソッドの使い勝手を改善していくのには結構な労力を必要としています。僕は僕自身が必要としている機能を優先的に作っているので、使い方によっては機能が足りない場合があるかもしれません。そういった場合は気軽に Pull Request を送ってもらえると嬉しいです