LoginSignup
19

More than 5 years have passed since last update.

google-api-ruby-clientでBigQuery使い方メモ

Last updated at Posted at 2016-05-26

rubyでgoogleのAPIを使うならgoogle-api-ruby-clientや他のラッパーしたgemを使用することがあると思いますが、google-api-ruby-client でBigQueryを扱うのに結構苦労したので忘れない為のメモになります。

今回のメモはbatchでbigqueryを叩く前提になります。
なのでフロント側でユーザー認証させたい場合は認証の仕方が変わりますのでご注意ください。

先に謝っておきます。当方rubyはまだ初心者なのでツッコミ歓迎です。

環境

  • centos6.7

事前準備に必要なもの

認証情報の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-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で使いたいという要件ならおそらく
* abronte/BigQuery
* ttanimichi/bigquery-client

を使ったほうが楽に扱えると思います。

exampleとかググってもアップデート後の使い方はほとんどありません

なのでruby初心者だけども、Gemの中身見まくって頑張りました。

BigQuery UIで動作確認をするときの注意事項

  • データセットの作成
  • データセットにテーブルを作成する

まではUIで確認できますが、テーブルにデータ投入後のデータの確認は人によって見れない場合があります。
僕はコレでAPIレスポンスが200なのにBigQuery UI でデータが入っていない現象(実際はbqで見れば入っていた)で半日ハマりました。。

データ投入の確認は BigQuery CommandLine Toolを使って確認することを強くおすすめします。

/path/to/hoge
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

/path/to/rails_root
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に記載しましょ

Gemfile
gem 'google-api-client'

bundle install

/path/to/rails_root
bundle install

認証をする

batch実行(rails runner)を想定した認証になります。
scopeは状況に応じて適切な設定を行ってください。

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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名を指定してください。

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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等をみれば、どういう定義があるかわかると思います。

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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データセットの中にあるテーブルを削除する

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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データの場合は容量単位で課金されますので、ご注意ください。

BigQuery 料金形態

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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

認証までまとめるとこんな感じ

/path/to/hoge/rails_root/lib/tasks/hoge.rb
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初心者のつぶやきです・・・・

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19