在Hadoop中使用NullWritable的优点

与使用null文本(即new Text(null) )相比,将NullWritable用于null键/值有什么好处。 我从“Hadoop:The Definitive Guide”一书中看到以下内容。

NullWritable是一种特殊类型的Writable ,因为它具有零长度序列化。 没有字节写入或读取流。 它用作占位符; 例如,在MapReduce中,当您不需要使用该位置时,可以将键或值声明为NullWritable – 它有效地存储常量空值。 当您想要存储值列表而不是键值对时,NullWritable也可以用作SequenceFile中的键。 它是一个不可变的单例:可以通过调用NullWritable.get()来检索实例

我不清楚如何使用NullWritable写出输出? 在开始输出文件中是否会有一个常量值,表明此文件的键或值为null ,以便MapReduce框架可以忽略读取null键/值(以null为准)? 另外,实际上如何序列化null文本?

谢谢,

Venkat

键/值类型必须在运行时给出,因此编写或读取NullWritables任何内容NullWritables将提前知道它将处理该类型; 文件中没有标记或任何内容。 从技术上讲, NullWritables是“读取”的,只是“读取” NullWritable实际上是一个无操作。 你可以亲眼看到没有任何书面或阅读:

 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 

至于你关于new Text(null)问题,你可以尝试一下:

 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将无法使用null String

我改变了run方法。 并取得成功

 @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; } 

你总是可以将你的字符串包装在你自己的Writable类中,并且有一个布尔表示它有空字符串:

 @Override public void readFields(DataInput in) throws IOException { ... boolean hasWord = in.readBoolean(); if( hasWord ) { word = in.readUTF(); } ... } 

 @Override public void write(DataOutput out) throws IOException { ... boolean hasWord = StringUtils.isNotBlank(word); out.writeBoolean(hasWord); if(hasWord) { out.writeUTF(word); } ... }