为什么Writable数据类型应该是可变的?
使用Text(vs String)作为Map,Combine,Shuffle或Reduce进程中Key / Value的数据类型有什么好处?
谢谢&问候,
拉贾
解决方法:
您无法选择,这些数据类型必须是可变的.
原因是序列化机制.我们来看看代码:
// version 1.x MapRunner#run()
K1 key = input.createKey();
V1 value = input.createValue();
while (input.next(key, value)) {
// map pair to output
mapper.map(key, value, output, reporter);
...
所以我们重新使用相同的键/值对实例.为什么?我不知道当时的设计决策,但我认为这是为了减少垃圾对象的数量.请注意,Hadoop已经很老了,当时垃圾收集器的效率还不如今天那么高,但即使在今天,如果要绘制数十亿个对象并直接将它们作为垃圾丢弃,它在运行时也会产生很大的不同.
你不能使Writable类型真正不可变的真正原因是你不能将字段声明为final.让我们用IntWritable做一个简单的例子:
public class IntWritable implements WritableComparable {
private int value;
public IntWritable() {}
public IntWritable(int value) { set(value); }
...
如果你将它变为不可变,它肯定不再适用于序列化过程,因为你需要定义值final.这不起作用,因为键和值是在运行时通过反射实例化的.这需要一个默认构造函数,因此InputFormat无法猜测填充最终数据字段所需的参数.因此,重用实例的整个概念显然与不变性的概念相矛盾.
但是,您应该问自己,Map / Reduce中不可变键/值应该具有哪些好处.在Joshua Bloch的 – Effective Java,第15项中,他指出不可变类更容易设计,实现和使用.而且他是对的,因为Hadoop的减速器是可变性最糟糕的例子:
void reduce(IntWritable key, Iterable<Text> values, Context context) ...
iterable中的每个值都指向同一个共享对象.因此,如果他们将他们的价值缓冲到正常的集合中并且问自己为什么它总是保留相同的值,那么很多人会感到困惑.
最后,它归结为性能的折衷(cpu和内存 – 假设一个键的数十亿个值对象必须驻留在RAM中)与简单性相比.