2011-11-15 5 views
7

J'ai un fichier dans lequel un ensemble de quatre lignes représente un enregistrement.Hadoop lit plusieurs lignes à la fois

par exemple, les quatre premières lignes représentent record1, quatre prochaines représentent fiche 2 et ainsi de suite ..

Comment puis-je assurer l'entrée Mapper ces quatre lignes à la fois?

, je veux aussi le partage de fichiers dans Hadoop pour arriver à la limite d'enregistrement (numéro de ligne doit être un multiple de quatre), de sorte que les dossiers ne reçoivent pas la durée dans plusieurs fichiers divisés ..

Comment cela peut-il être terminé?

Répondre

11

Quelques approches, certains plus sale que d'autres:


La bonne façon

Vous devrez peut-être définir votre propre RecordReader, InputSplit et InputFormat. Selon exactement ce que vous essayez de faire, vous serez en mesure de réutiliser certains des déjà existants des trois ci-dessus. Vous devrez probablement écrire votre propre RecordReader pour définir la paire clé/valeur et vous devrez probablement écrire votre propre InputSplit pour aider à définir la limite.


Une autre bonne façon, qui peut ne pas être possible

La tâche ci-dessus est assez intimidante. Avez-vous un contrôle sur votre ensemble de données? Pouvez-vous le pré-traiter d'une façon ou d'une autre (soit pendant qu'il arrive ou au repos)? Si c'est le cas, vous devriez envisager sérieusement de transformer votre jeu de données en quelque chose de plus facile à lire dans Hadoop.

Quelque chose comme:

ALine1 
ALine2   ALine1;Aline2;Aline3;Aline4 
ALine3 
ALine4  -> 
BLine1 
BLine2   BLine1;Bline2;Bline3;Bline4; 
BLine3 
BLine4 

Down and Dirty

Avez-vous un contrôle sur la taille des fichiers de vos données? Si vous divisez manuellement vos données sur la limite du bloc, vous pouvez forcer Hadoop à ne pas tenir compte des enregistrements couvrant des divisions. Par exemple, si la taille de votre bloc est de 64 Mo, écrivez vos fichiers en morceaux de 60 Mo. Sans vous soucier des divisions d'entrée, vous pourriez faire quelque chose de sale: Dans votre fonction de carte, ajoutez votre nouvelle paire clé/valeur dans un objet de liste. Si l'objet liste contient 4 éléments, effectuez le traitement, émettez quelque chose, puis nettoyez la liste. Sinon, n'émet rien et continue sans rien faire.

La raison pour laquelle vous devez diviser manuellement les données est que vous ne serez pas certain qu'un enregistrement entier à 4 lignes sera attribué à la même tâche cartographique.

+0

Merci pour votre réponse, je pensais à la deuxième approche que vous suggérez, mais est-ce pas aussi criblé avec le même problème? Comment lire quatre lignes à la fois pour les joindre et créer une seule ligne? – Gitmo

+0

Vous pourriez écrire quelque chose en Perl ou en Python qui pourrait faire l'affaire. C'est ce que j'avais en tête. –

+0

Utilisez [SequenceFile] (http://hadoop.apache.org/common/docs/current/api/org/apache/hadoop/io/SequenceFile.html) avec compression pour obtenir de meilleures performances si le pré-traitement du fichier est terminé . –

3

Une autre méthode (facile mais peut ne pas être efficace dans certains cas) consiste à implémenter le FileInputFormat#isSplitable(). Ensuite, les fichiers d'entrée ne sont pas divisés et sont traités un par carte.

import org.apache.hadoop.fs.*; 
import org.apache.hadoop.mapred.TextInputFormat; 
public class NonSplittableTextInputFormat extends TextInputFormat { 
    @Override 
    protected boolean isSplitable(FileSystem fs, Path file) { 
     return false; 
    } 
} 

Et comme orangeoctopus dit

In your map function, add your new key/value pair into a list object. If the list object has 4 items in it, do processing, emit something, then clean out the list. Otherwise, don't emit anything and move on without doing anything.

Cela a des frais généraux pour les raisons suivantes

  • Il est temps de traiter le fichier le plus grand fait glisser le temps d'achèvement des travaux.
  • De nombreuses données peuvent être transférées entre les nœuds de données.
  • Le cluster n'est pas correctement utilisé, car le nombre de cartes est égal au nombre de fichiers.

** Le code ci-dessus est de Hadoop : The Definitive Guide

+0

Merci! Mais j'utilise la nouvelle API .. – Gitmo

+0

Cette idée semble prometteuse. Que diriez-vous d'utiliser NLinesInputFormat pour spécifier le nombre de lignes à chaque mappeur. De cette façon, il ne dépendra pas du plus gros fichier. Le problème est, j'utilise Hadoop 0.20 qui n'a pas cette implémentation .. Des pensées? – Gitmo

+0

Dans 0.20 NLineInputFormat n'est pas implémenté dans la nouvelle API. Vous pouvez essayer de porter la nouvelle API NLinesInputFormat d'une autre version vers la version 0.20. Cela ne devrait pas être si difficile et vous apprendrez aussi comment compiler et construire un pot Hadoop. –

Questions connexes