Java用のシンプルでオープンソースのMap/Reduceフレームワーク/ APIを誰かが指摘できますか?そのようなものが存在するという証拠はあまりないようですが、他の誰かが違うことを知っているかもしれません。
私が見つけることができる最高のものはもちろん、Hadoop MapReduceですが、それは「単純な」基準を満たしていません。分散ジョブを実行する機能は必要ありません。標準のJava5スタイルの同時実行性を使用して、単一のJVMでマルチコアマシンでmap/reduceスタイルのジョブを実行できるようにするだけです。
自分で書くのは難しいことではありませんが、そうする必要はありません。
これらの問題はJava 8の時点での履歴であることに言及する価値があると思います。
int heaviestBlueBlock =
blocks.filter(b -> b.getColor() == BLUE)
.map(Block::getWeight)
.reduce(0, Integer::max);
つまり、単一ノードのMapReduceはJava 8)で利用可能です。
詳細については、 プロジェクトラムダに関するBrian Goetzのプレゼンテーション を参照してください。
Akka をチェックアウトしましたか? akkaは実際には分散アクタモデルベースの同時実行フレームワークですが、わずかなコードで簡単に多くのことを実装できます。作業を分割するのはとても簡単で、自動的にマルチコアマシンを最大限に活用し、複数のマシンを使用して作業を処理できます。スレッドを使用するのとは異なり、それは私にとってより自然に感じます。
Java map reduce example akkaを使用しています。futureを利用しているため、最も簡単なmap reduceの例ではありません。私のmap reduceの例が示すいくつかの主要な事柄があります:
ご質問があれば、StackOverflowには実際に素晴らしいakka QAセクションがあります。
私は次の構造を使用します
int procs = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(procs);
List<Future<TaskResult>> results = new ArrayList();
for(int i=0;i<tasks;i++)
results.add(es.submit(new Task(i)));
for(Future<TaskResult> future:results)
reduce(future);
これは事実の少し後かもしれませんが、JDK7の JSR166y ForkJoin クラスを見たいと思うかもしれません。
JDK6で問題なく動作するバックポートライブラリがあります。そのため、次の千年紀まで試してみる必要はありません。 raw executorとhadoopの間のどこかにあり、現在のJVM内でmap reduceジョブを処理するためのフレームワークを提供します。
数年前に8コアのマシンを手に入れたとき、私は自分のために1回限りのものを作成しましたが、それにはそれほど満足していませんでした。思ったほど簡単に使用できるとは思いませんでした。また、メモリを集中的に使用するタスクはうまく拡張できませんでした。
realの回答が得られない場合は、もっと共有できますが、その中心は次のとおりです。
public class LocalMapReduce<TMapInput, TMapOutput, TOutput> {
private int m_threads;
private Mapper<TMapInput, TMapOutput> m_mapper;
private Reducer<TMapOutput, TOutput> m_reducer;
...
public TOutput mapReduce(Iterator<TMapInput> inputIterator) {
ExecutorService pool = Executors.newFixedThreadPool(m_threads);
Set<Future<TMapOutput>> futureSet = new HashSet<Future<TMapOutput>>();
while (inputIterator.hasNext()) {
TMapInput m = inputIterator.next();
Future<TMapOutput> f = pool.submit(m_mapper.makeWorker(m));
futureSet.add(f);
Thread.sleep(10);
}
while (!futureSet.isEmpty()) {
Thread.sleep(5);
for (Iterator<Future<TMapOutput>> fit = futureSet.iterator(); fit.hasNext();) {
Future<TMapOutput> f = fit.next();
if (f.isDone()) {
fit.remove();
TMapOutput x = f.get();
m_reducer.reduce(x);
}
}
}
return m_reducer.getResult();
}
}
編集:コメントに基づいて、以下はsleep
なしのバージョンです。トリックは、CompletionService
を使用することです。これは、本質的に、完了したFuture
sのブロッキングキューを提供します。
public class LocalMapReduce<TMapInput, TMapOutput, TOutput> {
private int m_threads;
private Mapper<TMapInput, TMapOutput> m_mapper;
private Reducer<TMapOutput, TOutput> m_reducer;
...
public TOutput mapReduce(Collection<TMapInput> input) {
ExecutorService pool = Executors.newFixedThreadPool(m_threads);
CompletionService<TMapOutput> futurePool =
new ExecutorCompletionService<TMapOutput>(pool);
Set<Future<TMapOutput>> futureSet = new HashSet<Future<TMapOutput>>();
for (TMapInput m : input) {
futureSet.add(futurePool.submit(m_mapper.makeWorker(m)));
}
pool.shutdown();
int n = futureSet.size();
for (int i = 0; i < n; i++) {
m_reducer.reduce(futurePool.take().get());
}
return m_reducer.getResult();
}
また、これは、reduce操作とmerge操作の両方を実行する単一のreduceワーカーを含む、非常に蒸留されたmap-reduceアルゴリズムであることに注意してください。
Javaの並列処理に Skandium を使用するのが好きです。このフレームワークは、共有メモリを備えたマルチコアマシン向けの特定の並列処理パターン(つまり、マスタースレーブ、マップ/リデュース、パイプ、フォーク、分割統治)を実装しています。この手法は「アルゴリズムスケルトン」と呼ばれます。パターンはネストできます。
詳細には、骨格と筋肉があります。筋肉は実際の作業(分割、マージ、実行、および調整)を行います。スケルトンは、パターンをネストするときに役立つ「While」、「For」、および「If」を除き、並列処理のパターンを表します。
例はフレームワーク内にあります。筋肉と骨格の使い方を少し理解する必要がありましたが、このハードルを乗り越えた後、私はこのフレームワークが本当に好きです。 :)
GridGain をご覧になりましたか?
Functionals 4 JavaのプロジェクトWebサイトをご覧ください: http://f4j.rethab.ch/ フィルター、マップ、 8より前のJavaバージョンに減らします。
LeoTaskを試すことができます:並列タスク実行および結果集約フレームワーク
無料でオープンソースです: https://github.com/mleoking/leotask
そのAPIを示す簡単な紹介です: https://github.com/mleoking/leotask/blob/master/leotask/introduction.pdf?raw=true
これは、使用可能なすべてのCPUコアを使用して、単一のコンピューターで動作する軽量フレームワークです。
次の機能があります。
およびユーティリティ:
MapReduce APIがHazelcast v3.2に導入されました(ドキュメントの MapReduce APIセクションを参照 )。 Hazelcastは分散システムでの使用を目的としていますが、単一ノードのセットアップでは完全に機能し、かなり軽量です。