nigoblog

技術系会社のCEOブログ~私的編~

ビッグデータ取り扱いまでの流れ2 解析編

今回は収集したデータをどう解析していくか書いていきます。

解析にはHadoopを利用します。

Hadoopの動作環境はAmazon EMR (Elastic MapReduce)を使います。

  1. fluentdのインストール
  2. td-loggerでアプリケーションログの吐き出し
  3. td-loggerで受け取ったログをS3に送信
  4. S3のデータをHadoopで解析
  5. Hadoopで解析したデータをRDSに突っ込む

今回は前回の続きということでS3のデータをHadoopで解析から解説します。
Hadoopの処理はSQLライクに書けるHiveを利用します。

S3のデータをHadoopで解析

先程も書きましたが、EMRを利用します。
基本的にはコマンドラインのみでやっていきます。
なのでコマンドラインツールを予めインストールしといてください。

参考図書はこちら

Hadoopファーストガイド

Hadoopファーストガイド

EMRの起動

まずはEMRの起動から
認証系の設定ファイルを書きます
.credentials.jsonをホームディレクトリに追加。内容は以下です

{
  "access-id":     'AWSのkey',
  "private-key":   'AWSのsecret-key',
  "key-pair":      '公開鍵のファイル',
  "key-pair-file": '公開鍵のファイルのパス',
  'region': 'リージョン名[ap-northeast-1(東京)]',
  "log-uri":       ''
}

第3回 Amazon Elastic MapReduce Ruby ClientでEMRを起動する:Amazon Elastic MapReduceの使い方─Hadoopより手軽にはじめる大規模計算|gihyo.jp … 技術評論社
こちらが参考になります。

起動コマンドはこちら

elastic-mapreduce --create --alive --name "クラスター名" --key-pair "キーの名前" ¥
--instance-group master --instance-type m1.small --instance-count 1 ¥
--bid-price 0.02 ¥
--instance-group core --instance-type m1.small --instance-count 2 ¥
--bid-price 0.02 ¥
--hive-interactive

これで起動が完了です。
解説すると

--create で起動
--alive でシャットダウンを手動で行う設定
--name Hadoopクラスター名を指定
--key-pair インスタンスの鍵を指定
--instance-group master 詳しくは解説しませんが、hadoopにはmaster, core, taskのインスタンスグループがあります。masterとcoreは必ず必要です。
--instance-type インスタンスのサイズなどを指定します
--instance-count そのグループのインスタンス数を指定。masterは1つ。
--bid-price スポットインスタンスの入札価格 
--hive-interactive hiveを使うためのオプション。これがないとhiveが使えません。

スポットインスタンスに関して詳しくはこちら(
Amazon EC2 スポットインスタンス - Amazon EC2 (クラウド上の仮想サーバー Amazon Elastic Compute Cloud) | アマゾン ウェブ サービス(AWS 日本語))

確認は

elastic-mapreduce --list --active

としたとき

j-[jobflow_id]     WAITING        [public DNS][クラスター名]
   COMPLETED      Setup Hive   

このように
WAITING

COMPLETED
と表示されていれば利用できます。

hiveの利用

sshでmasterノードに入り作業をします

ssh -i [公開鍵のパス] hadoop@[public DNS]

ユーザーはhadoopユーザーを利用します。

sshでログイン後

hive

と入力します。するとhiveのコンソールが表示されます。
まずはS3からデータを取り込みます。(厳密には取り込むっていい方は違うっぽい(もうちょい詳しくなりたい))
イメージ的にはテーブルを作ってそこにS3のデータを取り込む
この辺はこちらを参考にしました。
はじめてのEMR/fluentdでS3にアップロードしたログをElastic MapReduceで検索・集計する | Developers.IO

CREATE EXTERNAL TABLE IF NOT EXISTS [テーブル名] (dt string, tag string, json string)
PARTITIONED BY ( PT STRING ) 
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'

このようなテーブルを作成します。

desc [テーブル名]

とすると

dt string
tag string
json string
pt string

このようなcolumn情報が表示されます。
前回の記事からログは

2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"piyo"}

このような感じになります。
なのでイメージ的には
dt 2014-03-29T00:40:11+09:00
tag my_app.test
json {"hoge" : "piyo"}
というデータが入っていきます。

ただこの段階ではソースは指定されていません。
ソースの指定はパーティションの追加により行います。
パーティションの追加は

ALTER TABLE [テーブル名] ADD IF NOT EXISTS PARTITION (pt = '[日付情報など]') LOCATION 's3://[S3のバケット名]'

このように行います。

ここまででhiveでS3に保存したデータを取り扱うことができます。

実際にSELECT文で色々試してみましょう

select * from [テーブル名];

とすると仮にS3の内容が

2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"piyo"}
2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"fuga"}

だとすると
そのまま

2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"piyo"}
2014-03-29T00:40:12+09:00	my_app.test	{"hoge":"fuga"}

と出てきます。
jsonが少々扱いにくいのでこのように書くとjsonの中身を利用できます。

select hoge
from [テーブル名] LATERAL VIEW json_tuple(テーブル名.json, hoge) j AS hoge

とすると

piyo
fuga

となります。
さらに条件もjsonの中身のやつを利用できます

select hoge
from [テーブル名] LATERAL VIEW json_tuple(テーブル名.json, hoge) j AS hoge
where hoge = "piyo"

とすると

piyo

のみが取り出せます。

前回のと組み合わせるとアプリケーションログを取得し、かつhiveにより利用出来るようになりました。

今回はボリュームが多くなってきたので、この辺で。
次回はこれらの処理をrubyから動作させる方法について書いていきたいと思います。

参考図書

この本は本当に参考になりました。まず最初に読むべき本かと思います。

Hadoopファーストガイド

Hadoopファーストガイド

ビッグデータ取り扱いまでの流れ1 収集編

最近ビッグデータを取り扱ってきているので、その流れを記録しようかと思います。
Ruby on Railsで構築していますが、一部以外は別の言語やフレームワークでも利用できます。

ビッグデータの定義ですが、この本の帯の「データサイズが悩みの種ならそれはもうビッグデータです」

Hadoopファーストガイド

Hadoopファーストガイド

っていうのがすごくしっくりきました。

丁度データサイズに悩み始めてきたため、ビッグデータを取り扱っているといえるでしょう。

ざっくりとした流れは

  1. fluentdのインストール
  2. td-loggerでアプリケーションログの吐き出し
  3. td-loggerで受け取ったログをS3に送信
  4. S3のデータをHadoopで解析
  5. Hadoopで解析したデータをRDSに突っ込む

というような流れとなっております。

fluentdのインストール

これはいろんなところで書いてあるのであまり深くは書きませんが、
こんな感じでインストールします。

/etc/yum.repos.d/td.repo

[treasuredata]
name=TreasureData
baseurl=http://packages.treasure-data.com/redhat/$basearch
gpgcheck=0
$ yum update
$ yum install td-agent

td-loggerでアプリケーションログの吐き出し

Gemfileにて

gem 'td-logger'

を追加しbundle install

ファイル
config/treasure_data.yml

development:
  agent: localhost:24224
  tag: アプリケーション名
  debug_mode: true  # enable debug mode

production:
  agent: localhost:24224
  tag: アプリケーション名
  debug_mode: false

# disable logging
test:

を追加

取得したい場所に

TD.event.post('[タグの名前]', ハッシュ)

するとログでは

datetime アプリケーション名.タグの名前 json

みたいな感じです。具体的に入れると

TD.event.post('test', { hoge: :piyo })

アプリケーション名をmy_appとするとログは

2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"piyo"}

みたいな感じになります。

td-loggerで受け取ったログをS3に送信

次は

2014-03-29T00:40:11+09:00	my_app.test	{"hoge":"piyo"}

こちらのログをS3に入れます。

設定ファイルに次の設定を追加します
/etc/td-agent/td-agent.conf

<match my_app.event>
  type s3
  aws_key_id AWSのキー
  aws_sec_key AWSのシークレットキー
  s3_bucket バケット名
  s3_endpoint S3のリージョン.amazonaws.com
  s3_object_key_format %{path}%{time_slice}_%{index}_%{hostname}.%{file_extension}
  path events/
  buffer_path /var/log/fluentd/events_s3
  time_slice_format %Y-%m-%d/%H
  time_slice_wait 10m 
</match>

これでオッケー。
あとはしばらく動かして、バケットの中身を見ると、gzip形式のファイルがどんどん溜まっていきます。
それをhadoopで処理します。

動いてないと思ったら

tail -f /var/log/td-agent/td-agent

などでログを見て行きましょう。

というわけで今回はここまで。
次回はhadoopで処理する方法を書いていきます。

参考記事

fluentd+rails+mongoでサクッとログ環境を整備してみる - dev.log

データサイエンティスト養成読本 [ビッグデータ時代のビジネスを支えるデータ分析力が身につく! ] (Software Design plus)

データサイエンティスト養成読本 [ビッグデータ時代のビジネスを支えるデータ分析力が身につく! ] (Software Design plus)

相対性理論とアジャイル開発の関係

今回はディレクター向けにアジャイル開発の難しい点を(特殊)相対性理論を用いて解説したいと思います。

おそらくタイトルの段階でどちらも理解している方は内容が想像つくのではないのでしょうか。

相対性理論について

もうこの名前だけでわけわからんって方が多いかと思いますが、一言で相対性理論を表すと
光速は不変
とにかくこれだけ抑えておけばこれから話す内容も理解できるかと。

これから、光速は不変ということをもう少し詳しく説明しますが、
その前に不変じゃない普通の速度について説明します。
まずある人Aが時速5kmで歩いているとします。
Aは電車の中にいて、この電車は時速80kmで動いているとします。
すると電車の外にいる人からするとAは時速85kmで動いている状態となります。
これが普通です。

次にAが光だったとします。
光なので光の速度 c で動きます。
光は電車の中にいて、この電車は時速80kmで動いているとします。
すると光は時速 c + 80 kmになるでしょうか。
答えはなりません。
理由はよくわかりませんが、これこそが相対性理論の光速不変たる所以です。

次にもう一度電車の例で例えます。
レーザー光を電車の床から天井に向けて照射したとします。
電車の中から見ている人のイメージはこちら
f:id:nigohiroki:20140317224223p:plain

電車が動いていると外から見ている人には光はこう見えます
f:id:nigohiroki:20140317224259p:plain

光の部分だけ取り出すと
f:id:nigohiroki:20140317224321p:plain
こんな感じになります。

長さ(移動距離)は速度 x 時間なので
光速 x 時間 が光の長さになります。

さて、この時光の長さが変わっているかと思います。
長い方を L1
短い方を L2
しかし光速は先ほど説明したように不変で c と定義します。
すると
L1 = c x 時間1
L2 = c x 時間2
となります。
L1 != L2 なので 時間1 != 時間2 です。
「あれ? 時間が違うってどういうこと?」
と思いますよね?
そのままの意味で、光速で動くものは動いていないものと比較し時間の進み方が違います。
つまり相対性理論を考えるとこの世で絶対的なものは光速であり、空間と時間は相対的だということです。

ちなみにこの理論を駆使すると速度と関係のある F=maや E = 1/2 mv^2なんかの速度以外が全て相対的になるため、速度が光速に近づくものは質量が無限に近づきます。

では次にアジャイル開発の話

アジャイル開発におけるスコープ

スコープは簡単にいうと機能です。あるプロジェクトにおいてプロジェクトを進めるにあたって考えなければいけないものが、

  • スコープ
  • リソース
  • 納期・リリース日

の3つがあります。
あるプロジェクトで実際に開発したことがある方はわかるかもしれませんが、

  • リソース
  • 納期・リリース日

は絶対的なものです。
リソースは減ることはあっても増えることはめったにありません。
納期・リリース日も特に受託の場合なんかは絶対に遅らせることは出来ません。

とすると、確実にスコープが揺らぐものとなります。

無理やり式に直すと
リリース日 - 現在の日 = スコープ x リソース
絶対的なリリース日とリソース、相対的なスコープという関係性が見えてくるかと思います。

2つの関係

ここまで見ていくと

  • 絶対的なもの
  • 相対的なもの

という2つのキーワードがあり
対応させると
光速 <=> リリース日、リソース
時間・空間 <=> スコープ
このような関係性が見えてきます。

ではこの関係性をどう活かしていこうかということですが、
これまで見てきたように光速は不変なものというのは物理学的に変わらない事実です。
そしてプロジェクトにおいてもリリース日、リソースは不変です。
つまりプロジェクトを成功させるにはいかにスコープを揺らがせてもいいかにかかっています。
設計の段階でスコープを不変のものにしてしまうとそのプロジェクトは絶対に炎上します。
スコープを変動させてプロジェクトがうまくいくようにどうディレクションしていくか。
これこそがアジャイル開発では重要なことです。

まとめ

特に構成も考えず書いていたら、相対性理論の説明いらなくね?みたいな記事になりました。
プロジェクトでも不要なスコープをどんどん削っていくことが重要ですね!
あとアジャイル開発においてリリース日を変動させる裏技も書いております。
詳しくはこちらの本を参考に!

アジャイルサムライ−達人開発者への道−

アジャイルサムライ−達人開発者への道−



正しい相対性理論

正しい相対性理論

MVCモデルで見るRubyとPHPの違い

約1年くらいPHPを触っていないのでもしかしたら的はずれなことを言ってしまうかもしれませんが、MVCモデルを例にとってRubyPHPの違いを自分なりに考えてみたいと思います。

自分が利用したことのあるフレームワーク
Ruby -> Rails
PHP -> CodeIgniter
なのでここから見ていきます。

ちなみにこれからダラダラと書きますが、結論は(個人的に)Rubyの方が優れているという内容を書きます。

MVCモデルについて、詳しく説明することもないのですが、RailsとCodeIgniterで大きく違う点を示したいと思います。
まずはCodeIgniterのMVCモデルから
f:id:nigohiroki:20140315143356p:plain
このようになっております。

次にRailsMVCモデル
f:id:nigohiroki:20140315143422p:plain
両者での大きな違いは

  1. Railsはviewに渡すのは変数ではなくオブジェクト
  2. Railsはviewからもモデルのメソッドを呼び出す

つまりRubyは全てのものがオブジェクトであるという点からPHPとはMVCの概念も異なるということが言えます。

仮にとあるWebサービスのユーザーランキングページを作るとします。
そのページにはユーザーのランキング情報プラス各ユーザーの詳細情報も見ることができます。

CodeIgniterではまずモデルにランキング情報を取得するメソッドを作成します。
同様にモデルにユーザーの詳細情報を取得するメソッドも作成します。
コントローラーでランキング情報を取得するメソッドを呼び出し、
結果をループさせユーザーの詳細情報が付与されたランキング情報のハッシュを作成します。
そのハッシュをviewに渡しforeachで表示させます。
イメージ的には

<?php
//モデル
function ranking{
  ~
  // {"rank" => , "user_id" => }
  return ranking_hash;
}
function user_info($user_id){
  ~
  // {"id" => , "name" => }
  return user_info_hash;
}
?>

<?php
//コントローラー
$ranking = $this->モデル->ranking;
foreach($ranking as $user){
  $user_data       = $this->モデル->user_info($user["user_id"]);
  $ranking_array = { "rank" => $user["rank"], "user" => $user_data } 
}
?>

//ビュー
<?php foreach($ranking_array as $user): ?>
<tr>
  <td><?php echo $user["rank"]; ?></td>
  <td><?php echo $user["user"]["name"]; ?></td>
</tr>
<?php endforeach; ?>

このような感じかと思います。

一方Railsで同様のことをすると
コントローラーでモデルのランキングメソッドを呼び出す
ビューでモデルの詳細メソッドを呼び出す
このようになります。

#モデル
def self.ranking
  ~
  ranking_object
end
def user_name
  self.name
end

#コントローラー
@ranking = モデル.ranking

#ビュー
<% @ranking.each do |rank, user| %>
<tr>
  <td><%= rank %></td>
  <td><%= user.user_name %></td>
</tr>
<% end %>

このような感じになります。CodeIgniterと比べるとコントローラーのやることがかなり減るかと思います。
また、そもそもコントローラーで@rankingとしなくても、ビュー側で

<% モデル.ranking.each do |rank, user| %>

というようにも書くことが出来ます。
ただこれは一長一短でもあり、ビューにプログラミング要素を入れ過ぎないようにすることも必要です。

メリット・デメリットを整理すると

メリット デメリット
CodeIgniter ビューのロジックが減るためデザイナーが扱いやすい コントローラーが肥大化する
Rails コントローラーがスッキリする デザイナーにもオブジェクト指向を理解してもらう必要がある

あとは色々パターンがあるためRailsの場合はチューニングがめんどくさそうです。
CodeIgniterの場合はコントローラーのベンチマークをとってチューニングするだけで良さそうですが。

まとめですが、個人的にはコントローラーがスッキリするRailsの方が好きだし優れていると感じます!

駆け足気味でしたが、MVCモデルを例にとってRubyPHPの違いを示してみました。

これから新たな言語を学ぶ方や、PHPをずっとやっている方はRubyを使ってみてはいかがでしょうか?

ちなみにずっとPHPをやっていた方は最初はコントローラーが長くなるかと思いますが、徐々に慣れていきスッキリとしたコントローラーになるでしょう。

Ruby on Rails 3 アプリケーションプログラミング

Ruby on Rails 3 アプリケーションプログラミング

Ruby on Rails環境構築ガイド

Ruby on Rails環境構築ガイド

Rails初心者から中級者になったと感じたきっかけ

エンジニア(プログラマー)をやっていると基本的には徐々にレベルアップしていきます。
しかしある点で閾値を越えて、レベルが一気に上がると感じる瞬間があります。
皆さんどうでしょうか?

自分の場合は
クラスメソッドとインスタンスメソッドの違いをはっきり理解したことがそのきっかけでした。

これまでぼんやりとモデルにメソッドを追加していたものがかなり自信を持ってメソッドを追加出来るようになりました。

今回はクラスメソッドとインスタンスメソッドの違いを簡単に紹介して、他にも初級者から中級者に上がるようなパターンを考えてみたいと思います。

クラスメソッドとインスタンスメソッドの違い

本当にその名の通りなんですが、
クラス全体で使えるのがクラスメソッド
あるクラスのインスタンスで使えるのがインスタンスメソッド
具体例を書くと、rubyでは

class Dog
    #クラスメソッド
    def self.choge
    end

    #インスタンスメソッド
    def ihoge
    end
end

このように書きます。とりあえずクラスはDog(犬)です。
クラスメソッドは self.メソッド名 という書き方をします。

メソッド内のselfの違い

これはこちらの記事が参考になります。
インスタンスメソッド内での self の値を調べた - (゚∀゚)o彡 sasata299's blog
クラスメソッド内ではオブジェクト、インスタンスメソッド内ではインスタンスとなります。
(解説していけば解説していくほどそのまんまだな)

呼び出し方の違い

呼び出し方は

#クラスメソッド
Dog.choge
#インスタンスメソッド
dog = Dog.new
dog.ihoge

のようになります。クラスメソッドはクラスからそのまま呼び出し、インスタンスメソッドはクラスのインスタンスから呼び出します。

使い方の違い

ここがある意味今回の記事一番のポイントかと思います。
説明するとこれまで同様、そのまんまの説明になるので、上記のDogを利用した具体例から。
クラスメソッドの場合

  • Dogのうち一番年齢の高いDogを取り出すメソッド
  • Dogのうちオスのみを取り出すメソッド

例えばこんな感じ

class Dog < ActiveRecord::Base
    # 一番年齢の高いDog
    def self.get_oldest
        self.order("age DESC").limit(1)
    end

    # オスのみを取り出す
    def self.get_male
        self.where(:sex => "male")
    end
end

要は「クラス全体の中から何かを取り出す」場合などに利用されます。

インスタンスメソッドの場合

  • とあるDogの年齢、性別をHashで取り出すメソッド
  • とあるDogの親のDogを取り出すメソッド(親が子のIDを持っているケース)
class Dog < ActiveRecord::Base
    # 年齢、性別
    def get_profile
        { :age => self.age, :sex => self.sex } 
    end

    # 親を取り出す
    def get_parent
        Dog.where(:child => self.id)
    end
end

こちらは「あるインスタンスの何かを取り出す」場合などに利用されます。インスタンスメソッドの場合は更新系もよく出てくるかと思います。

とりあえずここまででクラスメソッドとインスタンスメソッドの違いはなんとなくわかっていただけたかと。

初級者から中級者に上がるパターン

自分の場合は先に紹介したクラスメソッドとインスタンスメソッドの違いというところなのですが、
皆さんはいかがでしょうか?

などなどが考えられるかと思います。
というわけで今後はRails上級者目指して頑張って行きたいと思います!

パーフェクトRuby (PERFECT SERIES 6)

パーフェクトRuby (PERFECT SERIES 6)