不应该';t Hadoop集团<;键,(值列表)仅基于hashCode在reducer中?
我决定创建自己的WritableComparable类来学习Hadoop如何使用它。因此,我创建了一个带有两个实例变量(orderNumber cliente)的Order类,并实现了所需的方法。我还将Eclipse生成器用于getter/setter/hashCode/equals/toString 相比之下,我决定只使用orderNumber变量 我创建了一个简单的MapReduce作业,只是为了统计数据集中订单的出现次数。错误地,我的一个测试记录是Ita而不是Itá,正如您在这里看到的:不应该';t Hadoop集团<;键,(值列表)仅基于hashCode在reducer中?,hadoop,mapreduce,Hadoop,Mapreduce,我决定创建自己的WritableComparable类来学习Hadoop如何使用它。因此,我创建了一个带有两个实例变量(orderNumber cliente)的Order类,并实现了所需的方法。我还将Eclipse生成器用于getter/setter/hashCode/equals/toString 相比之下,我决定只使用orderNumber变量 我创建了一个简单的MapReduce作业,只是为了统计数据集中订单的出现次数。错误地,我的一个测试记录是Ita而不是Itá,正如您在这里看到的:
123 Ita
123 Itá
123 Itá
345 Carol
345 Carol
345 Carol
345 Carol
456 Iza Smith
Order [cliente=Ita, orderNumber=123] 3
Order [cliente=Carol, orderNumber=345] 4
Order [cliente=Iza Smith, orderNumber=456] 1
据我所知,第一条记录应被视为不同的顺序,因为记录1哈希代码与记录2和3哈希代码不同
但在reduce阶段,3个记录被分组在一起。正如你在这里看到的:
123 Ita
123 Itá
123 Itá
345 Carol
345 Carol
345 Carol
345 Carol
456 Iza Smith
Order [cliente=Ita, orderNumber=123] 3
Order [cliente=Carol, orderNumber=345] 4
Order [cliente=Iza Smith, orderNumber=456] 1
我认为它应该有一行记录,计数为2,Ita应该有计数为1
由于我在compareTo中只使用了orderNumber,所以我尝试在这个方法中使用字符串cliente(对下面的代码进行了注释)。然后,它像我期望的那样工作
那么,这是一个预期的结果吗?hadoop不应该只使用hashCode对键及其值进行分组吗
下面是Order类(我指定了getter/setter):
公共类顺序实现了可写性
{
私人客户;
私人长订单号;
@凌驾
public void readFields(DataInput in)引发IOException
{
cliente=in.readUTF();
orderNumber=in.readLong();
}
@凌驾
public void write(DataOutput out)引发IOException
{
外写(客户);
out.writeLong(订单号);
}
@凌驾
公共整数比较(o阶){
long thisValue=this.orderNumber;
long thatValue=o.orderNumber;
返回(thisValue>>32));
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
if(obj==null)
返回false;
如果(getClass()!=obj.getClass())
返回false;
订单其他=(订单)obj;
如果(客户==null){
if(other.cliente!=null)
返回false;
}如果(!客户等于(其他客户))
返回false;
if(orderNumber!=其他.orderNumber)
返回false;
返回true;
}
@凌驾
公共字符串toString(){
返回“Order[cliente=“+cliente+”,orderNumber=“+orderNumber+””;
}
以下是MapReduce代码:
public class TesteCustomClass extends Configured implements Tool
{
public static class Map extends MapReduceBase implements Mapper<LongWritable, Text, Order, LongWritable>
{
LongWritable outputValue = new LongWritable();
String[] campos;
Order order = new Order();
@Override
public void configure(JobConf job)
{
}
@Override
public void map(LongWritable key, Text value, OutputCollector<Order, LongWritable> output, Reporter reporter) throws IOException
{
campos = value.toString().split("\t");
order.setOrderNumber(Long.parseLong(campos[0]));
order.setCliente(campos[1]);
outputValue.set(1L);
output.collect(order, outputValue);
}
}
public static class Reduce extends MapReduceBase implements Reducer<Order, LongWritable, Order,LongWritable>
{
@Override
public void reduce(Order key, Iterator<LongWritable> values,OutputCollector<Order,LongWritable> output, Reporter reporter) throws IOException
{
LongWritable value = new LongWritable(0);
while (values.hasNext())
{
value.set(value.get() + values.next().get());
}
output.collect(key, value);
}
}
@Override
public int run(String[] args) throws Exception {
JobConf conf = new JobConf(getConf(),TesteCustomClass.class);
conf.setMapperClass(Map.class);
// conf.setCombinerClass(Reduce.class);
conf.setReducerClass(Reduce.class);
conf.setJobName("Teste - Custom Classes");
conf.setOutputKeyClass(Order.class);
conf.setOutputValueClass(LongWritable.class);
conf.setInputFormat(TextInputFormat.class);
conf.setOutputFormat(TextOutputFormat.class);
FileInputFormat.setInputPaths(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
JobClient.runJob(conf);
return 0;
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(),new TesteCustomClass(),args);
System.exit(res);
}
}
公共类TesteCustomClass扩展配置的实现工具
{
公共静态类映射扩展MapReduceBase实现映射器
{
LongWritable outputValue=新的LongWritable();
字符串[]campos;
订单=新订单();
@凌驾
公共无效配置(JobConf作业)
{
}
@凌驾
公共void映射(LongWritable键、文本值、OutputCollector输出、Reporter报告器)引发IOException
{
campos=value.toString().split(“\t”);
order.setOrderNumber(Long.parseLong(campos[0]));
order.setCliente(campos[1]);
输出值设置(1L);
收集(订单、输出值);
}
}
公共静态类Reduce扩展MapReduceBase实现Reducer
{
@凌驾
公共void reduce(顺序键、迭代器值、OutputCollector输出、报告器报告器)引发IOException
{
LongWritable值=新的LongWritable(0);
while(values.hasNext())
{
value.set(value.get()+values.next().get());
}
输出。收集(键、值);
}
}
@凌驾
公共int运行(字符串[]args)引发异常{
JobConf conf=newjobconf(getConf(),TesteCustomClass.class);
conf.setMapperClass(Map.class);
//conf.setCombinerClass(Reduce.class);
conf.setReducerClass(Reduce.class);
conf.setJobName(“Teste-自定义类”);
conf.setOutputKeyClass(Order.class);
conf.setOutputValueClass(LongWritable.class);
conf.setInputFormat(TextInputFormat.class);
conf.setOutputFormat(TextOutputFormat.class);
setInputPath(conf,新路径(args[0]);
setOutputPath(conf,新路径(args[1]);
runJob(conf);
返回0;
}
公共静态void main(字符串[]args)引发异常{
int res=ToolRunner.run(新配置(),新TesteCustomClass(),args);
系统退出(res);
}
}
默认的分区器是HashPartitioner
,它使用hashCode
方法来确定将K,V对发送到哪个减速机
在reducer中(或者如果您使用的是在map端运行的组合器),则使用compareTo
方法对键进行排序,然后还使用(默认情况下)比较是否应将顺序键分组在一起,并在同一迭代中减少它们的关联值
如果在
compareTo
方法中不使用cliente
键变量,而只使用orderNumber
变量,则具有相同orderNumber
的任何键都将一起减少其值,而不考虑cliente
值(您当前正在观察的值)默认的分区器是HashPartitioner
,它使用hashCode
方法来确定将K,V对发送到哪个减速机
在reducer中(或者如果您使用的是在map端运行的组合器),则使用compareTo
方法对键进行排序,然后还使用(默认情况下)比较是否应将顺序键分组在一起,并在同一迭代中减少它们的关联值
如果不使用cliente
关键变量,而只使用