Quelqu'un peut-il m'orienter vers un framework/API Map/Reduce simple et open-source pour Java? Il ne semble pas y avoir beaucoup de preuves d'une telle chose, mais quelqu'un d'autre pourrait en savoir différent.
Le meilleur que je puisse trouver est, bien sûr, Hadoop MapReduce, mais cela ne répond pas aux critères "simples". Je n'ai pas besoin de pouvoir exécuter des travaux distribués, juste quelque chose pour me permettre d'exécuter des travaux de mappage/réduction sur une machine multicœur, dans une seule machine virtuelle Java, en utilisant la concurrence simultanée de style Java5.
Ce n'est pas difficile d'écrire soi-même, mais je préfère ne pas avoir à le faire.
Je pense qu'il vaut la peine de mentionner que ces problèmes sont de l'histoire Java 8. Un exemple:
int heaviestBlueBlock =
blocks.filter(b -> b.getColor() == BLUE)
.map(Block::getWeight)
.reduce(0, Integer::max);
En d'autres termes: MapReduce à nœud unique est disponible en Java 8 .
Pour plus de détails, voir Présentation de Brian Goetz sur le projet lambda
Avez-vous vérifié Akka ? Alors que akka est vraiment un framework de concurrence basé sur un modèle d'acteur distribué, vous pouvez implémenter beaucoup de choses simplement avec peu de code. Il est tellement facile de diviser le travail en morceaux avec lui, et il tire automatiquement pleinement parti d'une machine multicœur, ainsi que de pouvoir utiliser plusieurs machines pour traiter le travail. Contrairement à l'utilisation de fils, cela me semble plus naturel.
J'ai un Java exemple de réduction de carte utilisant akka. Ce n'est pas l'exemple de réduction de carte le plus simple, car il utilise des futurs; mais il devrait vous donner une idée approximative de Il y a plusieurs choses importantes que mon exemple de réduction de carte démontre:
Si vous avez des questions, StackOverflow a en fait une impressionnante section akka QA.
J'utilise la structure suivante
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);
Je me rends compte que cela pourrait être un peu après coup, mais vous voudrez peut-être jeter un œil aux classes JSR166y ForkJoin de JDK7.
Il existe une bibliothèque à portage arrière qui fonctionne sous JDK6 sans aucun problème, vous n'avez donc pas à attendre le prochain millénaire pour l'essayer. Il se situe quelque part entre un exécuteur brut et hadoop donnant un cadre pour travailler sur la tâche de réduction de carte dans la JVM actuelle.
J'ai créé une pièce unique pour moi il y a quelques années lorsque j'ai eu une machine à 8 cœurs, mais je n'en étais pas très content. Je n'ai jamais réussi à le rendre aussi simple à utiliser que je l'avais espéré, et les tâches gourmandes en mémoire ne se sont pas bien adaptées.
Si vous n'obtenez pas de réponses réelles, je peux en partager plus, mais l'essentiel est:
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();
}
}
EDIT: Basé sur un commentaire, ci-dessous est une version sans sleep
. L'astuce consiste à utiliser CompletionService
qui fournit essentiellement une file d'attente de blocage des Future
s terminées.
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();
}
Je noterai également qu'il s'agit d'un algorithme de réduction de carte très distillé, comprenant un seul travailleur de réduction qui effectue à la fois l'opération de réduction et de fusion.
J'aime utiliser Skandium pour le parallélisme en Java. Le framework implémente certains modèles de parallélisme (à savoir Master-Slave, Map/Reduce, Pipe, Fork et Divide & Conquer) pour les machines multicœurs avec mémoire partagée. Cette technique est appelée "squelettes algorithmiques". Les motifs peuvent être imbriqués.
En détail, il y a des squelettes et des muscles. Les muscles font le travail réel (fractionner, fusionner, exécuter et conditionner). Les squelettes représentent les modèles de parallélisme, à l'exception de "Tant que", "Pour" et "Si", qui peuvent être utiles lors de l'imbrication de modèles.
Des exemples peuvent être trouvés à l'intérieur du cadre. J'avais besoin d'un peu pour comprendre comment utiliser les muscles et les squelettes, mais après avoir surmonté cet obstacle, j'aime vraiment ce cadre. :)
Avez-vous jeté un coup d'œil à GridGain ?
Vous voudrez peut-être jeter un œil au site Web du projet de Functionals 4 Java: http://f4j.rethab.ch/ Il introduit le filtre, la carte et le réduit à Java = versions antérieures à 8.
Vous pouvez essayer LeoTask: un cadre d'exécution de tâches parallèle et d'agrégation de résultats
Il est gratuit et open-source: https://github.com/mleoking/leotask
Voici une brève introduction montrant son API: https://github.com/mleoking/leotask/blob/master/leotask/introduction.pdf?raw=true
Il s'agit d'un framework léger fonctionnant sur un seul ordinateur utilisant tous ses cœurs CPU disponibles.
Il présente les fonctionnalités suivantes:
et utilitaires:
Une API MapReduce a été introduite dans la version 3.2 de Hazelcast (voir la section MapReduce API dans la documentation ). Bien que Hazelcast soit destiné à être utilisé dans un système distribué, il fonctionne parfaitement bien dans une configuration à nœud unique, et il est assez léger.