Quels sont les avantages de l’utilisation de NullWritable
pour les clés/valeurs null
par rapport à l’utilisation de textes null
(c.-à-d. new Text(null)
). Je vois ce qui suit dans le livre «Hadoop: Le guide définitif».
NullWritable
est un type spécial deWritable
, car il a une sérialisation de longueur nulle. Aucun octet n'est écrit ou lu dans le flux. Il est utilisé comme espace réservé. Par exemple, dans MapReduce, une clé ou une valeur peut être déclarée en tant queNullWritable
lorsque vous n’avez pas besoin d’utiliser cette position; elle stocke en réalité une valeur vide constante. NullWritable peut également être utile en tant que clé dansSequenceFile
lorsque vous souhaitez stocker une liste de valeurs, par opposition à des paires clé-valeur. C'est un singleton immuable: l'instance peut être récupérée en appelantNullWritable.get()
Je ne comprends pas clairement comment le résultat est écrit avec NullWritable
? Y aura-t-il une seule valeur constante dans le fichier de sortie de début indiquant que les clés ou les valeurs de ce fichier sont null
, de sorte que le cadre MapReduce puisse ignorer la lecture des clés/valeurs null
(selon la valeur null
)? De plus, comment les textes null
sont-ils sérialisés?
Merci,
Venkat
Les types clé/valeur doivent être spécifiés au moment de l'exécution. Ainsi, toute écriture ou lecture de NullWritables
saura à l'avance qu'il traitera avec ce type; il n'y a pas de marqueur ou quoi que ce soit dans le fichier. Et techniquement, les NullWritables
sont "lus", c’est juste que "lire" un NullWritable
est en réalité un no-op. Vous pouvez voir par vous-même qu'il n'y a rien du tout écrit ou lu:
NullWritable nw = NullWritable.get();
ByteArrayOutputStream out = new ByteArrayOutputStream();
nw.write(new DataOutputStream(out));
System.out.println(Arrays.toString(out.toByteArray())); // prints "[]"
ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
nw.readFields(new DataInputStream(in)); // works just fine
Et pour ce qui est de votre question sur new Text(null)
, encore une fois, vous pouvez l'essayer:
Text text = new Text((String)null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
text.write(new DataOutputStream(out)); // throws NullPointerException
System.out.println(Arrays.toString(out.toByteArray()));
Text
ne fonctionnera pas du tout avec un null
String
.
Vous pouvez toujours envelopper votre chaîne dans votre propre classe Writable et avoir un booléen indiquant qu'il a des chaînes vides ou non:
@Override
public void readFields(DataInput in) throws IOException {
...
boolean hasWord = in.readBoolean();
if( hasWord ) {
Word = in.readUTF();
}
...
}
et
@Override
public void write(DataOutput out) throws IOException {
...
boolean hasWord = StringUtils.isNotBlank(Word);
out.writeBoolean(hasWord);
if(hasWord) {
out.writeUTF(Word);
}
...
}
Je change la méthode d'exécution. et le succès
@Override
public int run(String[] strings) throws Exception {
Configuration config = HBaseConfiguration.create();
//set job name
Job job = new Job(config, "Import from file ");
job.setJarByClass(LogRun.class);
//set map class
job.setMapperClass(LogMapper.class);
//set output format and output table name
//job.setOutputFormatClass(TableOutputFormat.class);
//job.getConfiguration().set(TableOutputFormat.OUTPUT_TABLE, "crm_data");
//job.setOutputKeyClass(ImmutableBytesWritable.class);
//job.setOutputValueClass(Put.class);
TableMapReduceUtil.initTableReducerJob("crm_data", null, job);
job.setNumReduceTasks(0);
TableMapReduceUtil.addDependencyJars(job);
FileInputFormat.addInputPath(job, new Path(strings[0]));
int ret = job.waitForCompletion(true) ? 0 : 1;
return ret;
}