[Ruby on Rails]Treasure Dataにデータをbulk importする

2014.07.15

はじめに

前回、前々回に引き続き、Ruby on RailsにてTreasure Dataを使用する方法についてです。今回は大量のデータ(100Mを超える位?)をTreasure Dataにインポートするのに適した「bulk import」について書きたいと思います。

尚、本来はコマンドラインツールであるTreasure Data ToolbeltのコマンドをRailsから呼び出す形で行います。Rails(やRuby)から実行する理由は、ログの出力やメールの送信などTreasure Data以外の機能を柔軟に実装したい場合を考慮したためです。

bulk importについて

bulk importについては以下の公式ページの「Phases: Prepare, Upload, Perform and Commit」に分かりやすく説明されています。
Bulk Import Internal

bulk importで行う手順を簡単に纏めると

      1.アップロード対象のデータファイルを分割し、msgpack.gz形式にする
      2.msgpack.gz形式にしたファイルを全てアップロードする
      3.アップロードしたファイルをMapReduceを使い、行列の形式に変換する
      4.コミットする


となります。

サンプルソース

では、サンプルソースです。先に書いたbulk importの4つの手順を一つずつ行う方法と、一回のコマンドで行う方法の2種類あるのですが、今回は一回のコマンドで行う方法を採りました。

1.事前準備

まずTreasure Data Toolbeltをインストールします。その後、以下のコマンドでjarファイルを最新化します。

$ td import:jar_update

Treasure Data上にデータベース、テーブルを予め作成しておきます。

$ td db:create データベース名
$ td table:create データベース名 テーブル名

また後述するbulk importするコマンドをRailsより実行すると「`block in replace_gem': td is not part of the bundle. Add it to Gemfile. (Gem::LoadError)」というエラーが発生するため、Gemfileに以下を記述して bundle install します。(Treasure Data Toolbeltのコマンドを呼び出すためgemは関係ないはずなのですが・・・。詳細は不明です。)

gem 'td'

2.bulk import

最初に書いた通り、コマンドをRailsより実行します。これにはOpen3.capture3を使用します。

require "open3"

class Sample def self.import

cmd = "td import:auto " cmd << "--format csv --column-header " cmd << "--time-value #{Time.now.to_i.to_s} " cmd << "--auto-create sample_db.sample_strings " cmd << "-o ./parts/ " cmd << "./sample_strings.csv " out, err, status = Open3.capture3(cmd) true end end [/ruby]

6〜11行目が、bulk importするためのコマンドです。「td import:auto」を指定することで、一回のコマンドでbulk importを実現します。それ以外のコマンドオプションについては、以下の通りです。

  • --format csv インポートファイルのフォーマットとしてCSVを指定
  • --column-header CSVファイルにヘッダー有
  • --time-value TreasureDataのテーブルに存在するTime列に登録する値を指定
  • -o ./parts/ 「parts」フォルダにmsgpack.gzファイルを出力する
  • ./sample_strings.csv 「sample_strings.csv」をインポートする


上記以外にも様々なオプションを指定できます。それらについては以下のヘルプコマンドにて参照してみてください。

$ td help import:auto

13行目でコマンドを実行し、結果をout, error, statusの各変数に格納しています。outにはコマンドが標準出力する値が、errorはエラー時のみ値が格納されます。なのでout, errorの値を参照し、エラーにはログを出力するなどの処理をRailsにて実現することも可能です。

まとめ

以上でbulk importを実現することができました。今回は一回のコマンドでbulk importを実行しましたが、もっと細かい制御が必要な場合は、各コマンドを逐次実行することで実現できるかと思います。これらのコマンドやbulk importの詳細については、下記の公式のページを参照してください。

参考サイト

Bulk Import Internal
Bulk Import from CSV file