回答:
基本的には大きな問題ですが、難しくはありません。巡回セールスマンは、特定の都市間の距離に大きく依存しているため、多くの部分に分解できますが、部分的な結果を再結合できないため、グローバルに最適なソリューションが出現します(おそらくそうではありません。今すぐフィールドメダルを申請してください)。
一方、巨大なコーパス内の単語の頻度をカウントすることは自明区分可能であり、かつ自明recombinable(あなただけのコーパスのセグメントに対して計算ベクトルを加算)、その明白な解決策があるMAP-減らします。
実際には、多くの問題は簡単に再結合できる傾向があるため、タスクを並列化するかどうかの決定は、タスクの大きさに関係し、タスクの難しさには関係しません。
分散コンピューティングを使用して問題を効率的に解決できますか?
この質問に対する答えが「はい」の場合、MapReduceの問題の候補があります。これは、問題パターンが、より小さな孤立した問題に分割されるのに役立つためです。
あなたの仕事:この本を解析する
例はこれを説明するのにうまく機能します。大きな文書(Herby MelvilleのMoby Dick)があり、その仕事は、その中で使用されるすべての単語の頻度分析を実行することです。
シーケンシャルアプローチ
これを行うには、最速のマシン(たっぷり横たわっている)を取得し、最初から最後までテキストを実行して、検索するすべての単語(キー)のハッシュマップを維持し、毎回頻度(値)を増やします単語を解析します。シンプル、簡単、遅い。
MapReduceアプローチ
別の観点からこれにアプローチすると、これらすべての予備のマシンが横たわっており、このタスクをチャンクに分割できることに注意してください。各マシンに1Mbのテキストブロックを与えて、解析してハッシュマップにし、各マシンからのすべてのハッシュマップを照合して1つの結果にします。これは階層化されたMapReduceソリューションです。
テキストの行を読んで単語を収集するプロセスは、マップフェーズ(行内の単語をその頻度1、2、3などで表す単純なマップを作成する)であり、その後、各マシンが各行を照合するときの削減フェーズです。単一の集約マップにマップします。
全体的なソリューションは、すべての集約マップが最終マップに集約される(さらにその単語)さらに削減フェーズからもたらされます。少し複雑で、大規模な並列処理と高速処理。
概要
つまり、要約すると、問題がキー、値、それらの値の集計操作によって個別に表現される場合、MapReduceの問題の候補があります。
MapReduceパターンは、関数型プログラミングの世界から取られています。これは、データ構造にカタモフィズムと呼ばれるものを並行して適用するプロセスです。関数型プログラマは、ほとんどすべての単純な変換または要約にカタモフィズムを使用します。
データがツリーであると仮定すると、決定要因は、そのノードに含まれるデータとその子の計算値のみを使用してノードの値を計算できるかどうかです。
たとえば、カタモフィズムを使用してツリーのサイズを計算できます。すべての子の計算値に1を加えた合計を計算します。
このWPI-Map Reduce(ppt)のアプリケーションは興味があるかもしれません。MRのさまざまなアプリケーションについて説明します。また、議論されたケースの1つとして、100個のEC2インスタンスと24時間を使用して、New York Timesが4TBのスキャン記事を1.5TBのPDFドキュメントに変換する方法を示します。
MRがパフォーマンスの高速化に役立った別の例は次のとおりです。Aster-SQL Map Reduceは、不正検出、変換などを含むSQL-Map Reduceテクノロジーのケーススタディを示しています。
Map / Reduceは、特定の種類のアルゴリズムの特定の形式です。これを使用して、1つの巨大なデータセットを別のデータセットに変換します。(結果データセットは巨大な場合もそうでない場合もあります。)静的データ入力の結果として静的データ出力セットが必要ない場合、Map / Reduceは適切ではありません。Map / Reduceを使用すると、マンハッタンの電話帳に含まれるジョンスミスの数を簡単に確認できますが、Webサーバーの構築にはあまり適していません。
Map / Reduceの機能は次のとおりです。
その結果、(k1、v1)ペアのリストは(v3)のリストに変換されます。(もちろん、値「v3」は、k1に等しくなるように定義できるk2を含むコンポジットにすることができます。)
だからあなたはそれを使う:
1つまたは2つのサーバーを介してすべてを順番に実行することで開始するデータが大量にある場合、時間がかかりすぎます。
出力データは、値のリストまたはキーと値のペアであると考えることができます(「キー」は「一意のラベル」を意味することを覚えている場合は、それほど難しくありません)。
関係がどうであれ、各入力データが1つの出力キーの出力値にのみ影響することは確実です。
単一のサーバーですべてのデータを順番に処理できる場合、それが主要なコンピューティングパラダイム(サーバーの構築とプログラマーのトレーニング)であるため、単一のサーバーを使用します。
マップステージは、すべての入力データを出力キーで分割する必要があります。出力キーに関連付けられた出力値を生成する必要はありません(reduceステージで行われます)が、最大1つの出力キーの値に寄与するように、各入力キー値のペアを一意に割り当てる必要があります。データの相互関係が大きすぎる場合、map reduceは問題を処理できない可能性があります。一方、複数ラウンドのmap / reduceを使用する必要があるだけかもしれません。
データ変換をマップ/リデュースに変換する方法がわからない場合、もちろんそれは解決策ではありません。
問題をMap / Reduceが処理できるものに分解できるかどうかを判断するための本当の技術があります。たとえば、v1とv2が入力または出力データセットにまったくない場合があります。入力データ内の一意のアイテムをカウントする場合は、k1 = k2 =アイテムであり、v1 = v2 = 1または0または実際には何でもかまいません。reduceは、与えられたk2の数の合計としてv3を生成します。
そのため、Map / Reduceを使用してデータ変換を実行できないことを確実に言うことは困難ですが、上記はいくつかの指針を提供します。
MapReduceは、何らかの抽象化レベルで正確に2つの関数で構成されている問題に対して機能します。最初の関数は入力セットの各アイテムに適用され、2番目の関数は結果を集約します。
そのため、(n)入力から(1)結果を取得し、すべての入力を(1)関数で検査/使用できる場合はいつでも、MapReduceを使用できます。繰り返しますが、これは特定の抽象化レベルです。(1)関数は、入力をチェックし、他のいくつかの関数のどれを使用するかを決定するグループ化関数です。
これは、入力の量が事前にわからない場合、控えめな「単位」の作業を共有する必要がある場合、または結果全体を表す単一の戻り値が必要な場合(つまり、5,000単位のテストを実行する場合) 、x%未満が失敗した場合は成功を返します)。
ここでの答えのほとんどは、map reduceが何をするのかを説明するためのバリエーションのようです。これは有効です。しかし、map reduceを使用できる場所を示すパターンはどれであったかという質問に答えることは、実際には対処されていません。
あなたが見ている問題の素朴で非機能的な実装が何かをループし、ループの内側から何らかの状態でループの外側に何かを更新することを伴う場合、マップを減らすのに適切なポートがある可能性があります。特に、中央状態の更新を2つのパラメーターのみで機能する関数に一般化でき、この関数が可換および結合であることを保証できる場合。
trueの場合にmap reduceを使用する理由は2つあります。1)mapとreduce関数に分割すると、テストとデバッグが少し簡潔になり、簡単になります。2)map reduce関数はステートレスであり、同時に実行することができます。複数のcpusが利用可能で、それを利用してクラスター内で物事を実行するhadoopやsparkなどの場合、物事を高速化します。
これは、多くのものをループしている場合に便利ですが、マイレージはマップ/リデュースの複雑さによって異なる場合があります。最終的に、チェーンの最後の複雑な削減ステップですべてが依然としてボトルネックになっているシーケンシャルチェーンまたはマップ削減のツリーで終わることは非常に一般的です。たとえば、多くのグラフアルゴリズムは、マップの縮小だけでは効率的にスケーリングすることが困難です。
map reduceでうまく機能する最も単純な例は、ものを数えることです。これは非常に安価な削減です。これが、単語数がmap reduceでよく使用される例である理由です。そのユースケースを使用すると、パフォーマンスの線形スケーラビリティをほぼ期待できます。追加するすべてのCPUにより高速化されます。
多くの関数型プログラミングを行うと、一般的なマップとリデュースを必要とする状況に陥り始めます。あなたはおそらく命令型プログラミングでもそれらを見ますが、ループとアキュムレータのマスクの後ろでそれらを認識しません。
最近私に思いついたものの例として、私は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
Haskellには既に含まれunlines
ているので必要ありません[String]->String
)。私の主なポイントは、開始時にmap / reduceを使用することを予想していなかったということです。それは自分のニーズに合っているだけです。リストを使って何かをしたいので、リストを出力の単一の要素にしたかったのです。map / reduceの使用は自然に生まれました。
文字列処理(構文解析など)は、マップ削減の非常に明白な使用法の1つです。マッピングとは、入力テキストにさまざまな変換を適用し、結果テキストを出力として再びまとめることを削減することです。同様に、フォールドを使用して抽象構文ツリー要素のストリームをより良い形式に変換する(最適化する)コンパイラも同様です。
並列化可能ですか?
並列化可能な問題は、基本的にマップとフォールドです。逆に、マップステップは本質的に並列化可能であるため(折り畳むステップは、折り畳む構造によって異なります)、これは双方向のプロパティです。
サーバーのクラスターを検索していて、その時点で応答できないとします。mapReduceが行うことは、より大きなMapへのツリーノードにアクセスできなかったためです。後で再スケジュールし、MapまたはReduceを実行します。基本的に、環境内のソフトウェアとハードウェアの予測不能性により、すべての情報が利用可能であることを保証しようとします。
MapReduceを使用する(または使用しない)決定を調査するために使用する主な質問を次に示します。
解決しようとしている問題は、Map and Reduce操作に分解されますか?