不应该';t Hadoop集团<;键,(值列表)仅基于hashCode在reducer中?

不应该';t Hadoop集团<;键,(值列表)仅基于hashCode在reducer中?,hadoop,mapreduce,Hadoop,Mapreduce,我决定创建自己的WritableComparable类来学习Hadoop如何使用它。因此,我创建了一个带有两个实例变量(orderNumber cliente)的Order类,并实现了所需的方法。我还将Eclipse生成器用于getter/setter/hashCode/equals/toString 相比之下,我决定只使用orderNumber变量 我创建了一个简单的MapReduce作业,只是为了统计数据集中订单的出现次数。错误地,我的一个测试记录是Ita而不是Itá,正如您在这里看到的:

我决定创建自己的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
关键变量,而只使用