メイン関数のループを制御して、最初からやり直すかどうかを決定するグローバル ブール変数があります。決定は、条件が満たされた場合に変数が true に設定される reduce で行われます。次に、メインで、条件が満たされた場合、プログラム全体を再度実行します。これは 1 台のマシンで動作しますが、Amazon EC2 で実行しようとするとループしません。
3 に答える
問題は、EC2 では実際に分散モード (複数のマシン、それぞれが独自の JVM を実行) で実行しているのに対し、マシンではスタンドアロン モード (JVM が 1 つしか使用されていない) で実行していることです。
マシンでジョブを実行すると、hadoop フレームワークはクライアント (いわゆるドライバー)、map タスク、reduce タスクを同じ JVM で実行します。その結果、reduce 関数と main は同じグローバル変数で動作できるようになります。(ちなみに、Hadoop フレームワークはクライアント、マップ、実行を減らすために複数のオブジェクトを作成する可能性があるため、このグローバル変数は静的であるべきだと思います。静的にしなかった場合でもマシン上で動作する場合は、同じオブジェクト)。
EC2 でジョブを実行すると、クライアント、map タスク、reduce タスクが異なる JVM で実行されます。その結果、リデューサーは現在の JVM に存在するオブジェクトの「グローバル」変数を変更するため、クライアントを実行している JVM (JVM に存在するオブジェクトに独自のバージョンのグローバル変数を持つ) は、行われた変更を認識しません。レデューサーによって「グローバル」変数に。
グローバルを囲む引用符に注意してください。それらは、変数が期待するほどグローバルではないという事実を示しています。
その変数の値をファイルに書き込み、そのファイルを分散キャッシュに配置するか、ジョブの出力に変数の値を書き込むことによって、リデューサーからドライバー (メイン クラス) に変数を渡すことができます ( part-r-xxxx ファイル) を実際の出力/ペイロードから分離できる場合に備えて。
どちらの場合も、ドライバはキャッシュからファイルを取得するか、ジョブの出力ディレクトリから出力ファイルを取得できます。変数の値を読み取り、それに基づいて決定を下します。
特定の状態に到達したリデューサーの数を数えたい場合。ユーザー定義のカウンター (その状態に達すると、各レデューサーによってインクリメントされます) を使用でき、マッパーで解釈できます。Mapper.Context/Reducer.Context の getCounter() メソッドを使用して、その名前でカウンターにアクセスできます。
私はこれをカウンターで行うことになりましたが、それほどきれいではありませんが、機能します。2 つの変数 cnt と cnt1 を作成しました。条件が満たされた場合にインクリメントするカウンターを使用しました。cnt は、ジョブが最後にループされたときからのカウントを保持します。 cnt1 は、ジョブの後に更新されます。それらが同じである場合、再度ループすることはありません。これにより、すべてのジョブが 1 回余分に実行されますが、正しい出力が得られます。
助けてくれてありがとう。
Razvan が述べたように、マップ削減ジョブにグローバル変数を含めることはできません。これは、コードが多くのマシン (分散) ですべて並列に実行されているためです。サーバー A のリデュース ジョブは、マシン B で実行されているコードから完全に独立しています (MapReduce の場合も同様です)。再起動する前に、ジョブが終了するまで (成功するかどうかに関係なく) 待つ必要があります。完了するのを待つことができる場合は、構成に変数を設定するか、「グローバル変数」としてサーバーへのカウンターを使用して、ジョブが停止したときにそれを参照できます。HBase を使用している場合は、HBase に値を設定し、必要に応じてジョブの完了を読み取ることもできます。
あなたの状況は、まだセットアップしていない限り、HBase を少しやり過ぎにするかもしれません。
構成を設定するには、メイン ドライバー関数で次の手順を実行します。
conf.set("variableName",variableValue);
Mapper または Reducer で構成にアクセスするには:
Configuration conf = context.getConfiguration();
String variableValue = conf.get("variableName");
各マッパーまたはレデューサーは、別のマッパーまたはレデューサーによって変数に加えられた変更を認識しないことに注意してください。マッパーまたはリデューサー内で conf 変数を変更するかどうかさえわかりません-それはベストプラクティスではないかもしれません.
カウンターの場合、マッパーまたはリデューサーで次のことができます (カウンターを 1 ずつ増やします)。
context.getCounter("counterName").increment(new Long(1));
MR ジョブが完了したら、次の方法でカウンターを参照できます。
Counters counters = job.getCounters();
Counter counter = counters.findCounter("counterName");
long cntVal = counter.getValue();
繰り返しますが、MR ジョブの実行中ではなく、MR ジョブが完了した後にのみカウンター値を信頼できます。