无论如何,每个reducer进程是否可以确定它必须处理的元素或记录的数量?
答案 0 :(得分:3)
简短的回答 - 提前没有,减速器不知道可迭代支持多少个值。你可以做到这一点的唯一方法就是在迭代时计算,但你不能再重复迭代迭代。
长答案 - 支持iterable实际上是序列化键/值对的排序字节数组。减速器有两个比较器 - 一个用于按键顺序对键/值对进行排序,另一个用于确定键之间的边界(称为关键分组器)。通常,关键分组器与密钥排序比较器相同。
当迭代特定键的值时,底层上下文检查数组中的下一个键,并使用分组比较器与前一个键进行比较。如果比较器确定它们相等,则迭代继续。否则,此特定键的迭代结束。因此,您可以看到,您无法提前确定如何为任何特定密钥传递值。
如果你创建一个复合键,比如一个Text / IntWritable对,你实际上可以看到这个。对于compareTo方法,首先是Text,然后是IntWritable字段。接下来创建一个Comparator,用作组比较器,它只考虑键的Text部分。现在,当您迭代reducer中的值时,您应该能够观察每次迭代时键的IntWritable部分。
我之前用过的一些代码演示了这种情况,可以在pastebin
找到答案 1 :(得分:1)
您的reducer类必须扩展MapReducer Reduce类:
Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT>
然后必须使用扩展Reduce类中指定的KEYIN / VALUEIN参数实现reduce方法
reduce(KEYIN key, Iterable<VALUEIN> values,
org.apache.hadoop.mapreduce.Reducer.Context context)
与给定密钥关联的值可以通过
计算int count = 0;
Iterator<VALUEIN> it = values.iterator();
while(it.hasNext()){
it.Next();
count++;
}
虽然我建议在你的另一个处理过程中进行此计数,以便不会通过你的值集两次。
修改
这是一个向量的示例向量,它会在您添加时动态增长(因此您不必静态声明数组,因此不需要设置值的大小)。这对于非常规数据最有效(IE输入csv文件中每行的列数不相同),但开销最大。
Vector table = new Vector();
Iterator<Text> it = values.iterator();
while(it.hasNext()){
Text t = it.Next();
String[] cols = t.toString().split(",");
int i = 0;
Vector row = new Vector(); //new vector will be our row
while(StringUtils.isNotEmpty(cols[i])){
row.addElement(cols[i++]); //here were adding a new column for every value in the csv row
}
table.addElement(row);
}
然后你可以通过
访问第N行的第M列table.get(N).get(M);
现在,如果您知道将设置#列,您可以修改它以使用可能更快/更节省空间的数组向量。