[Ruby on Rails]td-clientでTreasureDataにデータをimportする

2014.07.14

はじめに

CSVファイルの中身を解析し、TreasureDataにimportするサンプルをRuby on Railsにて作成してみました。今回はTreasureDataの無料アカウントの作成と、importするサンプルソースについて書きたいと思います。

アカウントの作成

TreasureDataのページに行き、左の「製品」にフォーカスを当てると「今すぐ試す」というリンクが表示されます。この「今すぐ試す」リンクをまずはクリックします。

今すぐ試す

ページが遷移し、下のほうに赤字で「準備はよろしいですか?サインアップはこちらです。」のリンクがあるので、これをクリックします。すると以下のような画面が出るので、登録する情報を入力します。

signup

全ての項目が入力必須のようですが、注意点は電話番号を国際電話番号にする必要があるらしいことです。「03~」で始まる電話番号を入力した所、エラーとなったので、日本を示す「+81」を先頭につけて登録したところ上手く行きました。(尚、国際電話番号にする場合は03 → +813のように、+81の後ろの0を取り除いてください)

「Sign Up」のボタンを押すと、アカウント作成が完了します。

サンプルソース

では、サンプルソースについてです。今回はファイルの内容を一括で登録する「import」メソッドを使用しました。処理としては

  • CSVファイルを読み込む
  • ファイルの内容を元に、importするmsgpack.gz形式のファイルを作成する
  • 作成したmsgpack.gzファイルをimportする


を行っています。

尚、事前にTreasureData上にデータベースとテーブルが作成済みであることが前提です。

1.Gemfile

今回の処理に必要なgemをGemfileに記述し、$ bundle install します。

gem 'td'
gem 'td-client'
gem 'msgpack'

2.キーの取得

import処理を行うためには、TreasureDataより発行されるキーが必要です。このキーは、TreasureDataのページより確認することができます。TreasureDataのページにサインインした状態で、右上のユーザー名のリンクより「My Profile」をクリックします。Profileページの右側に「API Keys」という項目が表示されます。ここにパスワードを入力し、「Show Keys」ボタンを押下するとキーが表示されます。

api_key

もしくはTreasure Data Toolbeltがインストールされているなら、以下のコマンドでもキーを取得できます。

$ td apikey:show

3.import

先にimportする部分について解説します。サンプルソースは以下のようになります。

require 'csv'
require 'zlib'

class Sample
  TD_API_KEY = 'your api key'
  
  (中略)

  def self.import
    msgpack = create_msgpack(File.join(Rails.root, 'KEN_ALL_KAI.csv'))
    cln = TreasureData::Client.new(TD_API_KEY)
    File::open(msgpack) {|file|
      cln.import('sample_db', 'prefectures', 'msgpack.gz', file, 100)
    }
    true
  end

  (中略)
end

5行目の「TD_API_KEY」には上記で確認したキーを記述します。11行目でTreasureData::Clientのインスタンスを作成しています。12行目でインポートするmsgpack.gzファイルを開き、13行目でimportしています。

import()メソッドの構文ですが、以下のようになります。

import(データベース名, テーブル名, インポートするファイルの形式, インポートするファイルのストリーム, ファイルサイズ)

注意すべきなのは

  • インポートするファイルの形式はmsgpack.gzである
  • インポートするファイルのパスではなく、ストリームを渡す必要がある


ことです。

4.msgpack.gzファイルの作成

最後にmsgpack.gzファイルの作成の作成についてです。上記の12行目で呼ばれていたcreate_msgpack()メソッドになります。

private

  def self.create_msgpack(file_path)
    outfile_path = "#{file_path}.msgpack.gz"

    CSV.open(file_path, 'rb') {|csv|
      header = csv.take(1)[0]

      File.open(outfile_path, "wb") {|mspack|
        gz = Zlib::GzipWriter.new(mspack)

        csv.each do |row|
          i = 0
          data = Hash::new
          row.each do |item|
            data[header[i]] = item
            i = i + 1
          end

          data['time'] = Time.now.to_i

          gz.write(data.to_msgpack)
        end

        gz.close
      }
    }

    outfile_path

  end

こちらについては、以下のサイトを参考にさせて頂きました。ありがとうございました。
CSVからMessagePack形式への変換スクリプト

処理としては

  • CSVファイルをバイナリモードで開く
  • CSVファイルを解析しつつ、20行目で「Time」項目を追加する
  • msgpack.gzファイルに出力する


を行っています。「Time」項目を追加するのは、TreasureDataのテーブルにはデフォルトで「Time」カラムが存在するためです。

まとめ

以上でCSVファイルをTreasureDataにimportする処理を、Ruby on Railsにて実行することができました。私の環境で試したところ、13万件オーバーのCSVファイルが5秒以内に登録できました。尚、さらに件数が多い場合や、インポートするファイルサイズが大きい場合には「bulk_import」が適しているようです。これについても時間があれば書いてみようと思います。