私はしばらくMapReduceについて読んでいますが、理解できないのは、誰かがMapReduceを使用する(または使用しない)ことを決定する方法です。
つまり、MapReduceを使用できることを示す問題のパターンは何ですか。
それは基本的に大きな問題ですが、難しくはありません。 出張するセールスマンは、都市のペア間の距離に大きく依存するため、都市の多くの部分に分解できますが、部分的な結果を再結合できないため、グローバルに最適なソリューションが出現します(まあ、おそらく;方法がわかっている場合は、今すぐフィールズメダルを申請してください)。
一方、巨大コーパス内の単語の頻度のカウントは簡単に分割可能ですand簡単に再結合可能です(コーパスのセグメントに対して計算されたベクトルを合計するだけです)。したがって、map-reduceは明白です解決。
実際には、より多くの問題が容易に再結合可能である傾向があるため、タスクを並列化するかどうかの決定は、タスクの大きさに関係しており、タスクの難易度には関係ありません。
分散コンピューティングを使用して問題を効率的に解決できますか?
この質問に対する答えが「はい」の場合、MapReduceの候補となる問題があります。これは、問題のパターンが、より小さな孤立した問題に分割されるのに役立つためです。
あなたのタスク:この本を解析してください
例はこれを説明するのに適しています。大きなドキュメント( ハーマンメルビルのMoby Dick )があり、その中で使用されているすべての単語の頻度分析を実行するのが仕事です。
順次アプローチ
これは、最速のマシン(十分に横になっている)を取得し、テキストを最初から最後まで実行して、見つかったすべてのWord(キー)のハッシュマップを維持し、毎回頻度(値)をインクリメントすることにより、順次実行できます。単語を解析します。シンプルでわかりやすく、遅い。
MapReduceアプローチ
別の観点からこれにアプローチすると、これらすべての予備のマシンが横になっていて、このタスクをチャンクに分割できることに気付きます。各マシンに1Mbのテキストブロックを渡して、ハッシュマップに解析し、それぞれからのすべてのハッシュマップを単一の結果に照合します。これは階層化されたMapReduceソリューションです。
テキストの行を読み取って単語を収集するプロセスは、マップフェーズです(1、2、3などの頻度で行内の単語を表す単純なマップを作成します)。次に、各マシンが行を照合するときに、削減フェーズがあります。単一の集約マップにマップします。
全体的な解決策は、すべての集計マップが最終的なマップに(そのWordが再び)集計される、さらなるReduceフェーズから生じます。やや複雑で、非常に並列で高速です。
まとめ
つまり、要約すると、問題がキー、値、それらの値に対する集計操作によって分離して表現される場合、MapReduceの候補となる問題があります。
MapReduceパターンは、関数型プログラミングの世界からのものです。これは、カタモフィズムと呼ばれるものをデータ構造に並行して適用するプロセスです。関数型プログラマは、ほとんどすべての単純な変換または要約にカタモフィズムを使用します。
データがツリーであると仮定すると、決定要因は、ノードに含まれるデータとその子の計算値のみを使用してノードの値を計算できるかどうかです。
たとえば、カタモフィズムを使用して木のサイズを計算できます。すべての子の計算値に1を加えた合計を計算します。
これは WPI-Map Reduce(ppt)のアプリケーション に興味があるかもしれません。 MRのさまざまなアプリケーションについて説明します。また、検討したケースの1つとして、100のEC2インスタンスと24時間を使用して、ニューヨークタイムズが4 TBのスキャンされた記事を1.5 TBのPDFドキュメントに変換する方法を示しています。 。
MRがパフォーマンスの高速化に役立った別の例のセットは、次のとおりです。 Aster-SQL Map Reduce は、不正検出、変換などを含むSQL-Map Reduceテクノロジーのいくつかのケーススタディを示しています。
Map/Reduceは、特定の種類のアルゴリズムの特定の形式です。これを使用して、1つの巨大なデータセットを別のデータセットに変換します。 (結果のデータセットは巨大な場合とそうでない場合があります。)静的データ入力の結果として静的データ出力セットが必要ない場合は、Map/Reduceは適切ではありません。 Map/Reduceは、マンハッタンの電話帳にあるJohn Smithの数を簡単に教えてくれますが、Webサーバーの構築にはあまり適していません。
Map/Reduceの動作は次のとおりです。
その結果、(k1、v1)ペアのリストは(v3)のリストに変換されます。 (もちろん、値 "v3"はk2を含むコンポジットにすることができます。これはk1と等しくなるように定義できます。)
それであなたはそれを使う:
1つまたは2つのサーバーを介してすべてのデータを順番に実行するために開始する大量のデータがある場合、時間がかかりすぎます
出力データは、値のリストまたはキーと値のペアであると考えることができます(「キー」が「一意のラベル」のみを意味することを覚えていれば、一般的にそれほど難しくありません)。そして、
どのような関係であっても、入力データの各部分が1つの出力キーの出力値にのみ影響を与えることは確実です。
データをすべて単一のサーバーで順次処理できる場合は、それが主要なコンピューティングパラダイム(サーバーが構築され、プログラマーがトレーニングを受けるもの)であるため、単一のサーバーを使用します。
マップステージは、すべての入力データを出力キーで分割する必要があります。出力キーに関連付けられた出力値を生成する必要はありませんが(reduceステージで行われます)、最大で1つの出力キーの値に寄与するために、各入力キー値のペアを一意に割り当てる必要があります。データが相互に関連しすぎている場合、マップ削減は問題を処理できない可能性があります。一方、map/reduceを複数回使用する必要がある場合もあります。
データ変換をマップ/リデュースに変換する方法がわからない場合は、もちろんそれは解決策ではありません。
問題をMap/Reduceが処理できるものに分解できるかどうかを判断する本当の芸術があります。たとえば、v1とv2が入力または出力データセットにまったくない場合があります。入力データ内の一意のアイテムを数える場合は、k1 = k2 =アイテムで、v1 = v2 = 1または0または実際には何でもかまいません。 Reduceは、指定されたk2の数の合計としてv3を生成します。
そのため、Map/Reduceを使用してデータ変換を実行できないとは言い難いですが、上記はいくつかの指針となります。
ここでの答えのほとんどは、map reduceが何を行うかを説明するバリエーションであるようですが、これは有効です。しかし、どのパターンがmap reduceを使用できるかを示すパターンであるという質問に答えることは、実際にはそれによって対処されていません。
あなたが見ている問題の素朴で非機能的な実装が何かをループし、ループの外側から何かをループの内側からある状態で更新することを伴う場合、マップするのに適したポートを削減する可能性があります。特に、中央状態の更新を2つのパラメーターのみで機能する関数に一般化でき、この関数が可換的かつ連想的であることを保証できる場合。
Trueの場合にmap reduceを使用する理由は2つあります。1)物事をmapとreduce関数に分解すると、テストとデバッグが少しわかりやすくなり、簡単になる場合があります。 2)map reduce関数はステートレスであり、同時に実行される可能性があります。これにより、複数のcpusが利用可能で、hadoopやsparkを使用してクラスター内で実行する場合など)の場合にスピードアップします。
たくさんのものをループしているならこれはいいですが、あなたのマイレージはあなたのマップ/リデュースがどれだけ複雑であるかによって異なります。最終的にシーケンシャルチェーンまたはマップ削減のツリーになることがよくあります。最終的には、チェーンの最後にある複雑な削減ステップですべてがまだボトルネックになっています。たとえば、多くのグラフアルゴリズムは、map reduceだけでは効率的にスケーリングすることが困難です。
Map reduceでうまく機能する最も単純な例は、ものを数えることです。これは非常に安価な削減です。これが、単語数がマップ削減のよく使用される例である理由です。そのユースケースを使用すると、パフォーマンスの線形スケーラビリティがほぼ期待できます。追加するすべてのCPUによって、高速化されます。
MapReduceは、あるレベルの抽象化で正確に2つの関数で構成される問題に対処します。最初の関数は入力セットの各アイテムに適用され、2番目の関数は結果を集計します。
したがって、(1)入力から(1)結果を取得する必要があり、すべての入力を(1)関数で検査/使用できる場合はいつでも、MapReduceを使用できます。繰り返しますが、これは特定の抽象化レベルです。 (1)関数は、入力をチェックし、他のいくつかの関数のどれを使用するかを決定するいくつかのグループ化関数です。
これは、入力の量が事前にわからない場合、作業の目立たない「単位」を共有する必要がある場合、または結果全体を表す単一のリターンが必要な場合(IEで5000ユニットテストを実行する場合)に役立ちます。 、そしてx%未満が失敗した場合、成功を返します)。
多くの関数型プログラミングを行う場合、一般的なマップを必要とする状況に遭遇し、削減します。命令型プログラミングでそれらを見ることさえあるかもしれませんが、ループとアキュムレータのマスクの後ろでそれらを認識しません。
最近思いついた例として、Haskellでパーサーに取り組んでいます。パーサーをテストするために、パーサーを介して文字列フラグメントのリストをポンプで送ります。次に、結果を出力して、正しく解析されたかどうかを確認できる単一の文字列を取得します。だからそれは次のようになります:
--my initial set of test data, a list
tests = ["string1", "string2", "string3", ...]
--Map Step: turn strings into parsed results
--note the type, which demonstrates the map
applyParser :: [String] -> [Token]
--The actual function
applyParser input = map parser input
--Second map, turn tokens into output
showTokens :: [Token] -> [String]
showTokens t = map show t
--Reduce step, concat the results
combineResults :: [String] -> String
--In haskell, reduce is the foldl function, which takes an operation to fold with, a starting element, and a list to fold on
combineResults strings = foldl concat "" strings
--Finished program
testParser = print (combineResults(showTokens(applyParser tests)))
もちろん、これは教育的なものです。私の実際のコードは少し異なって見え、より多くの内部関数を使用します(fold concat
は、[String]->String
を実行するunlines
がすでに含まれているため、必要ありません)。私の主なポイントは、私が始めたときにmap/reduceを使用することを予想していなかったということでした。リストを使っていくつかのことを行い、リストを出力の単一の要素にしたかったのです。 map/reduceの使用は自然に浮上しました。
文字列処理(解析など)は、マップ削減の非常に明らかな使用法の1つです。マッピングは、入力テキストにさまざまな変換を適用し、削減して、結果テキストを再び出力として戻します。同様に、コンパイラーも同様で、折りたたみを使用して抽象構文ツリー要素のストリームをより適切な形式(最適化)に変換します。
以下は、MapReduceを使用する(または使用しない)決定を調査するために使用する主な質問です。
解決しようとしている問題はMap and Reduce操作に分解されますか?
サーバーのクラスターを検索していて、その時点で応答できないとします。 mapReduceが行うのは、そのツリーノードに大きなMapへアクセスできなかったためです。後で再スケジュールして、MapまたはReduceを実行します。基本的に、環境内のソフトウェアとハードウェアの予測不可能な状態ですべての情報が利用可能であることを保証しようとします。
並列可能ですか?
並列処理可能な問題は、本質的にはマップとフォールドです。逆に、マップステップは本質的に並列化可能であり(折りたたみの構造によっては、折りたたみステップが可能である場合があります)、これは双方向プロパティです。
実際、これは一般的な「分割統治」パターンであるため、計算を分散するためのソリューションを一般的に記述できます。
簡単な例は、大きなドキュメントのようなものです。問題は、その文書の文字数を数えることです。 1台のマシンで実行する代わりに、ドキュメント内のすべての単語の配列に分解できます。その後、各Wordを個別に処理し、結果を一緒に戻すことができます。
汎用的なmap/reduce実装が機能するようになったら、同じソフトウェアレイヤーを使用して問題を解決できるため、パターンを使用して問題を表現する必要があるだけです。