CouchDBの質問に関連しています。
誰もが麻痺者が理解できる言葉でMapReduceを説明できますか?
CouchDBの質問に関連しています。
誰もが麻痺者が理解できる言葉でMapReduceを説明できますか?
回答:
MapとReduceの基本について説明します。
マップは、ある種類のリストの項目を別の種類の項目に「変換」して、同じ種類のリストに戻す関数です。
数字のリストがあるとします:[1,2,3]すべての数字を2倍にしたい場合、この場合、「すべての数字を2倍にする」関数は関数x = x * 2です。マッピングなしで、次のように書くことができます単純なループ、言う
A = [1, 2, 3]
foreach (item in A) A[item] = A[item] * 2
そして、私はA = [2、4、6]を持っていますが、ループを書く代わりに、マップ関数があれば、書くことができます
A = [1, 2, 3].Map(x => x * 2)
x => x * 2は、[1,2,3]の要素に対して実行される関数です。何が起こるかというと、プログラムは各項目を取得し、xを各項目に等しくすることで(x => x * 2)を実行し、結果のリストを生成します。
1 : 1 => 1 * 2 : 2
2 : 2 => 2 * 2 : 4
3 : 3 => 3 * 2 : 6
(x => x * 2)でマップ関数を実行すると、[2、4、6]になります。
Reduceは、リスト内の項目を「収集」し、それらすべてに対して何らかの計算を実行して、それらを単一の値に減らす関数です。
合計または平均を見つけることはすべて、reduce関数のインスタンスです。たとえば、[7、8、9]のように数値のリストがあり、それらを合計したい場合は、次のようなループを作成します。
A = [7, 8, 9]
sum = 0
foreach (item in A) sum = sum + A[item]
しかし、reduce関数にアクセスできる場合は、次のように書くことができます。
A = [7, 8, 9]
sum = A.reduce( 0, (x, y) => x + y )
ここで、2つの引数(0と、xとyを使用する関数)が渡される理由が少しわかりにくいです。reduce関数が役立つためには、2つのアイテムを取得して何かを計算し、その2つのアイテムを1つの単一の値に「削減」できる必要があります。したがって、プログラムは、単一の値になるまで各ペアを削減できます。
実行は次のようになります。
result = 0
7 : result = result + 7 = 0 + 7 = 7
8 : result = result + 8 = 7 + 8 = 15
9 : result = result + 9 = 15 + 9 = 24
ただし、常にゼロから開始する必要はないので、最初の引数は、シード値、具体的には最初のresult =
行の値を指定できるようにするためのものです。
2つのリストを合計したい場合、次のようになります。
A = [7, 8, 9]
B = [1, 2, 3]
sum = 0
sum = A.reduce( sum, (x, y) => x + y )
sum = B.reduce( sum, (x, y) => x + y )
または、あなたが現実の世界で見つける可能性が高いバージョン:
A = [7, 8, 9]
B = [1, 2, 3]
sum_func = (x, y) => x + y
sum = A.reduce( B.reduce( 0, sum_func ), sum_func )
Map \ Reduceサポートを使用すると、データをDBに格納してそれを使用する方法を知らなくてもデータベースを操作できるので、DBソフトウェアの良い点です。それがDBエンジンの目的です。
Map関数またはReduce関数のいずれかを使用して、必要なものをエンジンに "伝える"ことができれば、DBエンジンはデータの周りに方法を見つけ、関数を適用し、結果を思い付くことができます。すべてのレコードをループする方法を知らなくても、すべてが必要です。
インデックス、キー、結合、ビュー、および単一のデータベースが保持できる多くのものがあるため、データが実際に格納される方法からユーザーを保護することにより、コードの作成と保守が容易になります。
並列プログラミングの場合も同じです。ループコードを実際に実装するのではなく、データで何をしたいかを指定するだけで、基盤となるインフラストラクチャが同時並列ループで関数を「並列化」して実行できます。
Average()
はおそらく上に着氷していSum()
ます。しかし、私はそれが関数が「リデュース」と呼ばれる理由を説明するためにそれについて話しました...平均関数は、数のリストを取り、それを単一の数(平均)に減らすものです。
MapReduceは、開発者がマッパー以外のコードを記述して関数を削減することなく、膨大な量のデータを並列処理する方法です。
マップ機能は、データを取得し、バリアに保持される結果、アウト解約します。この関数は、多数の同じマップタスクと並行して実行できます。次に、データセットをスカラー値に縮小できます。
SQLステートメントのように考えると
SELECT SUM(salary)
FROM employees
WHERE salary > 1000
GROUP by deptname
mapを使用して、給与が1000を超える従業員のサブセットを取得できます。このマップは、バリアからグループサイズのバケットに排出されます。
Reduceは、それらの各グループを合計します。結果セットを提供します。
グーグルペーパーの私の大学の研究ノートからこれを摘採しました
ステップ2はマップです。ステップ3は削減です。
例えば、
MapReduceがMapとReduceに分割されている理由は、さまざまな部分を並行して簡単に実行できるためです。(特に、Reduceに特定の数学的特性がある場合。)
MapReduceの複雑でありながら優れた説明については、GoogleのMapReduceプログラミングモデル-再考(PDF)を参照してください。
MAPとREDUCEは、人間が最後の恐竜を殺したときからの古いLisp関数です。
あなたが名前、そこに住んでいる人の数、そして都市の大きさに関する情報を持つ都市のリストを持っていると想像してください:
(defparameter *cities*
'((a :people 100000 :size 200)
(b :people 200000 :size 300)
(c :people 150000 :size 210)))
ここで、人口密度が最も高い都市を見つけることができます。
まず、MAPを使用して都市名と人口密度のリストを作成します。
(map 'list
(lambda (city)
(list (first city)
(/ (getf (rest city) :people)
(getf (rest city) :size))))
*cities*)
=> ((A 500) (B 2000/3) (C 5000/7))
REDUCEを使用すると、人口密度が最大の都市を見つけることができます。
(reduce (lambda (a b)
(if (> (second a) (second b))
a
b))
'((A 500) (B 2000/3) (C 5000/7)))
=> (C 5000/7)
両方を組み合わせると、次のコードが得られます。
(reduce (lambda (a b)
(if (> (second a) (second b))
a
b))
(map 'list
(lambda (city)
(list (first city)
(/ (getf (rest city) :people)
(getf (rest city) :size))))
*cities*))
関数を紹介しましょう:
(defun density (city)
(list (first city)
(/ (getf (rest city) :people)
(getf (rest city) :size))))
(defun max-density (a b)
(if (> (second a) (second b))
a
b))
次に、MAP REDUCEコードを次のように記述します。
(reduce 'max-density
(map 'list 'density *cities*))
=> (C 5000/7)
MAP
and REDUCE
(評価は裏返しです)を呼び出すので、map reduceと呼ばれます。
max-density
渡された引数の2番目の要素を比較しますよね?ばかげた編集でごめんなさい。
Googleペーパーの例を見てみましょう。MapReduceの目標は、ある種のアルゴリズムに対して並列で動作する処理ユニットの負荷を効率的に使用できるようにすることです。例は次のとおりです。一連のドキュメントからすべての単語とその数を抽出するとします。
典型的な実装:
for each document
for each word in the document
get the counter associated to the word for the document
increment that counter
end for
end for
MapReduceの実装:
Map phase (input: document key, document)
for each word in the document
emit an event with the word as the key and the value "1"
end for
Reduce phase (input: key (a word), an iterator going through the emitted values)
for each value in the iterator
sum up the value in a counter
end for
その周りには、一連のドキュメントを「スプリット」に分割するマスタープログラムがあり、マップフェーズで並行して処理されます。発行された値は、ワーカーに固有のバッファーにワーカーによって書き込まれます。次に、マスタープログラムは、バッファーの処理準備ができたことが通知されるとすぐに、他のワーカーにリデュースフェーズの実行を委任します。
すべてのワーカー出力(MapまたはReduceワーカー)は、実際には分散ファイルシステム(GFS for Google)またはCouchDBの分散データベースに格納されたファイルです。
MapReduce の非常に簡単、迅速、かつ「初心者向け」の紹介は、http://www.marcolotz.com/? p = 67で入手できます。
コンテンツの一部を投稿する:
まず第一に、なぜMapReduceが最初に作成されたのですか?
基本的にGoogleは、ネットワークを介して接続された多数のマシンにデータを分散できるように、大規模な計算ジョブを簡単に並列化できるソリューションを必要としていました。それとは別に、マシンの障害を透過的に処理し、負荷分散の問題を管理する必要がありました。
MapReduceの真の強みは何ですか?
MapReduceの魔法はMap関数とReduce関数のアプリケーションに基づいていると言えるかもしれません。私はメイトを告白しなければなりません、私は強く同意しません。MapReduceを非常に人気にした主な機能は、シンプルなインターフェースと組み合わせた、自動並列化と配布の機能です。これらの要因と、ほとんどのエラーに対する透過的な障害処理の合計により、このフレームワークは非常に人気がありました。
紙のもう少し深み:
MapReduceは、Googleの論文(Dean&Ghemawat、2004年–リンクはこちら)で、並列アプローチとコモディティコンピュータークラスターを使用してビッグデータで計算を行うソリューションとして最初に言及されました。Javaで記述されたHadoopとは対照的に、GoogleのフレームワークはC ++で記述されています。このドキュメントでは、大規模なデータセットに対する関数型プログラミングのMap関数とReduce関数を使用して、並列フレームワークがどのように動作するかについて説明します。
このソリューションでは、MapとReduceと呼ばれる2つの主要なステップがあり、最初と2番目の間にオプションのステップがあり、Combineと呼ばれます。Mapステップが最初に実行され、入力Key-Valueペアで計算を実行して、新しい出力Key-Valueを生成します。入力キーと値のペアの形式は、必ずしも出力形式のペアと一致する必要はないことに注意してください。Reduceステップは、同じキーのすべての値をアセンブルし、それに対して他の計算を実行します。その結果、この最後のステップではキーと値のペアが出力されます。MapReduceの最も簡単なアプリケーションの1つは、単語数を実装することです。
このアプリケーションの疑似コードを以下に示します。
map(String key, String value):
// key: document name
// value: document contents
for each word w in value:
EmitIntermediate(w, “1”);
reduce(String key, Iterator values):
// key: a word
// values: a list of counts
int result = 0;
for each v in values:
result += ParseInt(v);
Emit(AsString(result));
お気づきのように、マップはレコード内のすべての単語(この場合、レコードは行にすることができます)を読み取り、その単語をキーとして、数値1を値として出力します。その後、reduceは同じキーのすべての値をグループ化します。例を挙げましょう。レコードに「家」という単語が3回出現するとします。レデューサーの入力は[house、[1,1,1]]です。レデューサーでは、キーハウスのすべての値を合計し、出力として次のキー値を提供します:[house、[3]]。
これは、MapReduceフレームワークでこれがどのように表示されるかを示すイメージです。
MapReduceアプリケーションのいくつかの他の古典的な例として、次のように言うことができます。
•URLアクセス頻度の数
•逆Webリンクグラフ
•分散Grep
•ホストごとの用語ベクトル
大量のネットワークトラフィックを回避するために、このペーパーでは、フレームワークがデータの局所性を維持する方法を説明しています。これは、マップジョブを実行しているマシンのデータがメモリ/ローカルストレージにあることを常に確認し、ネットワークからのフェッチを回避する必要があることを意味します。マッパーの配置によりネットワークを削減することを目的として、前述のオプションのコンバイナーステップが使用されます。Combinerは、レデューサーに送信する前に、特定のマシンのマッパーの出力に対して計算を実行します。これは別のマシンにある場合があります。
このドキュメントでは、障害が発生した場合のフレームワークの要素の動作についても説明しています。論文では、これらの要素をワーカーとマスターと呼びます。それらは、オープンソース実装では、より具体的な要素に分割されます。グーグルはこのアプローチを紙で説明しただけで、独自のソフトウェアをリリースしなかったため、モデルを実装するために多くのオープンソースフレームワークが作成されました。例として、HadoopまたはMongoDBの制限されたMapReduce機能を言うことができます。
ランタイムは、入力データのパーティショニング、マシンの大規模なセット全体でのプログラム実行のスケジューリング、マシン障害の処理(もちろん、透過的な方法)、マシン間通信の管理など、専門家以外のプログラマーの詳細を処理する必要があります。入力データがワーカー間でどのように分割されるかについて、経験豊富なユーザーはこれらのパラメーターを調整できます。
重要な概念:
• フォールトトレランス:マシンの障害を適切に許容する必要があります。これを実行するために、マスターは定期的にワーカーにpingします。マスターが一定の時間内に特定のワーカーからの応答を受信しない場合、マスターはそのワーカーで作業が失敗したと定義します。この場合、障害のあるワーカーによって完了したすべてのマップタスクは破棄され、別の使用可能なワーカーに渡されます。ワーカーがまだマップまたは削減タスクを処理していた場合も同様です。ワーカーが既に削減部分を完了している場合は、失敗するまでにすべての計算がすでに完了しており、リセットする必要がないことに注意してください。障害の主なポイントとして、マスターに障害が発生すると、すべてのジョブが失敗します。このため、データ構造を保存するために、マスターの定期的なチェックポイントを定義できます。
• 局所性:ネットワークトラフィックを回避するために、フレームワークは、すべての入力データが計算を実行するマシンでローカルに利用できることを確認しようとします。元の説明では、レプリケーション係数が3に設定され、ブロックサイズが64 MBのGoogleファイルシステム(GFS)を使用しています。これは、64 MBの同じブロック(ファイルシステム内のファイルを構成する)が、3つの異なるマシンで同一のコピーを持つことを意味します。マスターはブロックがどこにあるかを知っており、そのマシンでマップジョブをスケジュールしようとします。それが失敗した場合、マスターはタスク入力データのレプリカの近くにマシンを割り当てようとします(つまり、データマシンの同じラック内のワーカーマシン)。
• タスクの細分性:各マップフェーズがM個に分割され、各削減フェーズがR個に分割されていると仮定すると、MとRがワーカーマシンの数よりもはるかに大きいことが理想的です。これは、さまざまなタスクを実行するワーカーが動的負荷分散を改善するという事実によるものです。それとは別に、ワーカーが失敗した場合の回復速度が向上します(完了した多くのマップタスクを他のすべてのマシンに分散できるため)。
• バックアップタスク: MapまたはReducerワーカーは、クラスター内の他のワーカーよりも動作がはるかに遅い場合があります。これは、合計処理時間を保持し、単一の遅いマシンの処理時間と等しくなる場合があります。元のペーパーでは、バックアップタスクと呼ばれる代替方法について説明しています。これは、MapReduce操作が完了に近づいたときにマスターによってスケジュールされます。これらは、進行中のタスクのマスターによってスケジュールされたタスクです。したがって、プライマリまたはバックアップが完了すると、MapReduce操作が完了します。
• カウンター:イベントの発生をカウントしたい場合があります。このため、作成された場所をカウントします。各ワーカーのカウンター値は定期的にマスターに伝達されます。次に、マスターは成功したマップとリデュースタスクのカウンター値を集計し(そうです。プレゲルアグリゲーターはこの場所から来たようです)、MapReduce操作が完了するとユーザーコードに返します。マスターステータスでは現在のカウンター値も利用できるため、プロセスを監視している人間は、プロセスの動作を追跡できます。
さて、私は上記のすべての概念で、Hadoopがあなたにとって簡単なものになると思います。MapReduceの元の記事や関連することについて質問がある場合は、お知らせください。
Pythonに精通している場合は、MapReduceの可能な最も簡単な説明を以下に示します。
In [2]: data = [1, 2, 3, 4, 5, 6]
In [3]: mapped_result = map(lambda x: x*2, data)
In [4]: mapped_result
Out[4]: [2, 4, 6, 8, 10, 12]
In [10]: final_result = reduce(lambda x, y: x+y, mapped_result)
In [11]: final_result
Out[11]: 42
生データの各セグメントがどのように個別に処理されたかを確認します。この場合は、2(MapReduceのマップ部分)が乗算されます。基づいてmapped_result
、我々は結果があろうと結論付けた42
(削減のMapReduceの一部)。
この例からの重要な結論は、処理の各チャンクが別のチャンクに依存しないという事実です。たとえば、thread_1
maps [1, 2, 3]
とthread_2
mapsの場合[4, 5, 6]
、両方のスレッドの最終的な結果は変わりません[2, 4, 6, 8, 10, 12]
が、処理時間は半分になりました。同じことは、reduceオペレーションについても言え、MapReduceが並列計算でどのように機能するかの本質です。