web-dev-qa-db-fra.com

Simple Java Framework Map / Reduce

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.

49
skaffman

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

11
Lukas Eder

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:

  • Comment diviser le travail.
  • Comment attribuer le travail: akka a un système de messagerie très simple était bien un partionnaire de travail, dont vous pouvez configurer l'horaire. Une fois que j'ai appris à l'utiliser, je n'ai pas pu m'arrêter. C'est tellement simple et flexible. J'utilisais les quatre cœurs de mon processeur en un rien de temps. C'est vraiment génial pour implémenter des services.
  • Comment savoir quand le travail est terminé et que le résultat est prêt à être traité: c'est en fait la partie qui peut être la plus difficile et la plus déroutante à comprendre, à moins que vous ne soyez déjà familier avec Futures. Vous n'avez pas besoin d'utiliser Futures, car il existe d'autres options. Je les ai juste utilisés parce que je voulais quelque chose de plus court pour les gens.

Si vous avez des questions, StackOverflow a en fait une impressionnante section akka QA.

18
chaostheory

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);
10
Peter Lawrey

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.

8
Gareth Davis

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 Futures 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.

6
xan

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. :)

5
Florian Pilz

Avez-vous jeté un coup d'œil à GridGain ?

3
Costi Ciudatu

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.

3
rethab

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:

  • Exploration d'espace de paramètres automatique et parallèle
  • Agrégation de résultats flexible et basée sur la configuration
  • Modèle de programmation axé uniquement sur la logique clé
  • Récupération d'interruption fiable et automatique

et utilitaires:

  • Structures de réseaux dynamiques et clonables.
  • Intégration avec Gnuplot
  • Génération de réseau selon des modèles de réseau courants
  • DelimitedReader: un lecteur sophistiqué qui explore les fichiers CSV (valeurs séparées par des virgules) comme une base de données
  • Générateur de nombres aléatoires rapide basé sur l'algorithme de Mersenne Twister
  • Un CurveFitter intégré du projet ImageJ
0
user4432445

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.

0
skaffman