Upload
yuya-takeyama
View
9.612
Download
3
Embed Size (px)
DESCRIPTION
以下のスライドを再編集・一部加筆した Short Version ですhttp://www.slideshare.net/taketyan/php-mysql-mapreduce
Citation preview
PHP と MySQL でカジュアルに
MapReduce する(Short Version)
@yuya_takeyama
ショートバージョンでお送りします
• MyMR on GitHubhttps://github.com/yuya-takeyama/mymr
• PHP と MySQL でカジュアルに MapReduce するhttp://blog.yuyat.jp/archives/1706
• もっとカジュアルに PHP と MySQL で MapReduce するhttp://blog.yuyat.jp/archives/1853
• PHP と MySQL でカジュアルに MapReduce する(スライド・Long Version)http://www.slideshare.net/taketyan/php-mysql-mapreduce
お断り
ビッグデータの話はありません
問い
MongoDB にあってMySQL にないもの
なーんだ?
構造化データ?自動シャーディング?自動フェイルオーバ?
MapReduce!
MapReduce!それもカジュアルな!!
MongoDB はJavaScript で
カジュアルにMapReduce できる
MySQL でもMapReduce
したい!!!
MySQL でもMapReduce
したい!!!
それもカジュアルに!!
モチベーション•プログラミングモデルとしてのMapReduce を使いたい
•GROUP BY では難しい集計•MySQL を入出力にしたい
•LL でサクッとやりたい
モチベーション•プログラミングモデルとしてのMapReduce を使いたい
•GROUP BY では難しい集計•MySQL を入出力にしたい
•LL でサクッとやりたいPHP である必要はあまり無い
MapReduce とは(word count による例)
MapReduce とは
データ処理のためのプログラミングモデル
処理の流れ入力↓
Map↓
Shuffle↓
Reduce↓出力
Map
•入力データを受け取り•複数の Key/Value ペアを出力
•to be or not to be
•<"to", 1>
•<"be", 1>
•<"or", 1>
•<"not", 1>
•<"to", 1>
•<"be", 1>
Shuffle
•Map による Key/Value を
•Key ごとにまとめて出力
•<"to", 1>
•<"be", 1>
•<"or", 1>
•<"not", 1>
•<"to", 1>
•<"be", 1>
•<"be", [1, 1]>
•<"not", [1]>
•<"or", [1]>
•<"to", [1, 1]>
Reduce
•Shuffle による中間データを•集約して答えを出力
•<"be", [1, 1]>
•<"not", [1]>
•<"or", [1]>
•<"to", [1, 1]>
•<"be", 2>
•<"not", 1>
•<"or", 1>
•<"to", 2>
複数の関数の入出力を経て最終的な答えを出力
MySQL でもMapReduce したい!!! (再)
というわけで作りました
MyMR
•MySQL を入出力とする
•PHP で Map/Reduce を書く
•コマンドラインで実行
https://github.com/yuya-takeyama/mymr
MyMR による処理の流れ•テーブルからレコードを読む•1 行 1 行に Map (PHP) を適用して中間テーブルへ
•MySQL による Shuffle
•その結果に Reduce (PHP) を適用して出力テーブルへ
文章中の単語の数を数える例(word count)
MyMR による
use \MyMR\Builder;
$builder = new Builder;
$builder->setInputTable('root@localhost/db/texts');$builder->setOutputTable('root@localhost/db/word_counts');
$builder->setMapper(function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }});
$builder->setReducer(function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);});
return $builder;
Map/Reduce の定義
use \MyMR\Builder;
$builder = new Builder;
$builder->setInputTable('root@localhost/db/texts');$builder->setOutputTable('root@localhost/db/word_counts');
$builder->setMapper(function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }});
$builder->setReducer(function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);});
return $builder;
Map/Reduce の定義
入出力テーブルの指定
use \MyMR\Builder;
$builder = new Builder;
$builder->setInputTable('root@localhost/db/texts');$builder->setOutputTable('root@localhost/db/word_counts');
$builder->setMapper(function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }});
$builder->setReducer(function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);});
return $builder;
Map/Reduce の定義
この辺が Map
use \MyMR\Builder;
$builder = new Builder;
$builder->setInputTable('root@localhost/db/texts');$builder->setOutputTable('root@localhost/db/word_counts');
$builder->setMapper(function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }});
$builder->setReducer(function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);});
return $builder;
Map/Reduce の定義
この辺が Reduce
入力
•to be or not to be
function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }}
Map
function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }}
レコードを連想配列として受け取る
Map
function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }} text カラム内の
文字列をスペースで分割
Map
function ($record, $emitter) { $words = preg_split('/\s+/u', $record['text']); foreach ($words as $word) { $emitter->emit($word, 1); }}
Key/Value のペアとして中間テーブルに INSERT
Map
Map+----+--------------------+| id | text |+----+--------------------+| 1 | to be or not to be |+----+--------------------+
↓ レコードを連想配列として Map へ ↓+----+---------+-------+ | id | key | value | +----+---------+-------+ | 1 | to | 1 | | 2 | be | 1 | | 3 | or | 1 | | 4 | not | 1 | | 5 | to | 1 | | 6 | be | 1 | +----+---------+-------+
Map+----+--------------------+| id | text |+----+--------------------+| 1 | to be or not to be |+----+--------------------+
↓ レコードを連想配列として Map へ ↓+----+---------+-------+ | id | key | value | +----+---------+-------+ | 1 | to | 1 | | 2 | be | 1 | | 3 | or | 1 | | 4 | not | 1 | | 5 | to | 1 | | 6 | be | 1 | +----+---------+-------+
value には JSON で入れるので構造化データも使用可能
Shuffle
↓ キーで GROUP BY して ↓↓ 値は GROUP_CONCAT ↓
+---------+--------+| key | values |+---------+--------+| be | 1,1 || not | 1 || or | 1 || to | 1,1 |+---------+--------+
+----+---------+-------+ | id | key | value | +----+---------+-------+ | 1 | to | 1 | | 2 | be | 1 | | 3 | or | 1 | | 4 | not | 1 | | 5 | to | 1 | | 6 | be | 1 | +----+---------+-------+
SELECT `key`, GROUP_CONCAT(`value`)FROM `中間テーブル`
GROUP BY `key`
function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);}
Reduce
function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);}
ReduceKey Value の配列
function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);}
ReduceValue を全て足す
function ($key, $values) { $sum = 0; foreach ($values as $count) { $sum += $count; } return array('count' => $sum);}
Reduce
返り値の連想配列をレコードとして INSERT
Reduce
↓ キーと値の配列を Reduce へ ↓
+---------+--------+| key | values |+---------+--------+| be | 1,1 || not | 1 || or | 1 || to | 1,1 |+---------+--------+
+----+---------+-------+| id | key | count |+----+---------+-------+| 1 | be | 2 || 2 | not | 1 || 3 | or | 1 || 4 | to | 2 |+----+---------+-------+
Reduce
↓ キーと値の配列を Reduce へ ↓
+---------+--------+| key | values |+---------+--------+| be | 1,1 || not | 1 || or | 1 || to | 1,1 |+---------+--------+
+----+---------+-------+| id | key | count |+----+---------+-------+| 1 | be | 2 || 2 | not | 1 || 3 | or | 1 || 4 | to | 2 |+----+---------+-------+
実際にはデリミタとして改行を使用改行区切りの JSON になる
今後の目標
•非同期 INSERT による並列化•Hadoop へのシームレスな移行方法の提供
今後の野望
•V8 エンジンとかで•ストレージエンジン API を•カジュアルに叩いて•MapReduce したい
ご清聴ありがとうございました