【问题标题】:combiner and reducer can be different?组合器和减速器可以不同吗?
【发布时间】:2012-07-28 17:27:15
【问题描述】:

在许多 MapReduce 程序中,我看到一个 reducer 也被用作组合器。我知道这是因为这些程序的特殊性质。但我想知道它们是否可以不同。

【问题讨论】:

    标签: mapreduce reducers combiners


    【解决方案1】:

    是的,combiner 可以与 Reducer 不同,尽管您的 Combiner 仍将实现 Reducer 接口。组合器只能用于依赖于工作的特定情况。 Combiner 将像 Reducer 一样运行,但仅限于每个 Mapper 输出的 Key/Values 子集。

    与 Reducer 不同,Combiner 将具有的一个约束是输入/输出键和值类型必须与 Mapper 的输出类型匹配。

    【讨论】:

    【解决方案2】:

    这是实现,你可以在没有组合器和组合器的情况下运行,两者都给出完全相同的答案。这里Reducer和Combiner有不同的动机和不同的实现。

    package combiner;
    
    import java.io.IOException;
    
    
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    public class Map extends Mapper<LongWritable, Text, Text, Average> {
    
    Text name = new Text();
    String[] row;
    
    protected void map(LongWritable offSet, Text line, Context context) throws IOException, InterruptedException {
        row = line.toString().split(" ");
        System.out.println("Key "+row[0]+"Value "+row[1]);
        name.set(row[0]);
        context.write(name, new Average(Integer.parseInt(row[1].toString()), 1));
    }}
    

    减少类

    public class Reduce extends Reducer<Text, Average, Text, LongWritable> {
        LongWritable avg =new LongWritable();
        protected void reduce(Text key, Iterable<Average> val, Context context)throws IOException, InterruptedException {
        int total=0; int count=0; long avgg=0;
    
        for (Average value : val){
            total+=value.number*value.count;
            count+=value.count;
            avgg=total/count;   
            }
        avg.set(avgg);
        context.write(key, avg);
    }
    }
    

    地图对象类

    public class Average implements Writable {
    
    long number;
    int count;
    
    public Average() {super();}
    
    public Average(long number, int count) {
        this.number = number;
        this.count = count;
    }
    
    public long getNumber() {return number;}
    public void setNumber(long number) {this.number = number;}
    public int getCount() {return count;}
    public void setCount(int count) {this.count = count;}
    
    @Override
    public void readFields(DataInput dataInput) throws IOException {
        number = WritableUtils.readVLong(dataInput);
        count = WritableUtils.readVInt(dataInput);      
    }
    
    @Override
    public void write(DataOutput dataOutput) throws IOException {
        WritableUtils.writeVLong(dataOutput, number);
        WritableUtils.writeVInt(dataOutput, count);
    
    }
    }
    

    组合器类

    public class Combine extends Reducer<Text, Average, Text, Average>{
    
    protected void reduce(Text name, Iterable<Average> val, Context context)throws IOException, InterruptedException {
        int total=0; int count=0; long avg=0;
    
        for (Average value : val){
            total+=value.number;
            count+=1;
            avg=total/count;    
            }
        context.write(name, new Average(avg, count));
    
    }
    }
    

    驱动类

    public class Driver1 {
    
    public static void main(String[] args) throws Exception { 
    
        Configuration conf = new Configuration();
        if (args.length != 2) {
            System.err.println("Usage: SecondarySort <in> <out>");
            System.exit(2);
        }
        Job job = new Job(conf, "CustomCobiner");
        job.setJarByClass(Driver1.class);
        job.setMapperClass(Map.class);
        job.setCombinerClass(Combine.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Average.class);
        job.setReducerClass(Reduce.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);     
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
    }
    

    here获取代码

    留下你的建议..

    【讨论】:

      【解决方案3】:

      组合器的主要目标是优化/最小化键值对的数量 在 mapper 和 reducer 之间通过网络进行洗牌,从而节省最多 带宽。

      combiner 的经验法则是它必须具有相同的输入和输出变量类型,原因 为此,不保证组合器的使用,可以使用或不可以使用,具体取决于音量 和泄漏次数。

      reducer 在满足这个规则时可以用作组合器,即相同的输入和输出 变量类型。

      combiner 的另一个最重要的规则是它只能在你想要的功能时使用 to apply 既可交换又可结合。喜欢添加数字。但不是平均情况(如果你使用与 reducer 相同的代码)。

      现在回答你的问题,是的,当然它们可以不同,当你的减速器有不同类型的输入和输出变量时,你别无选择,只能制作你的减速器代码的不同副本并修改它。

      如果你关心 reducer 的逻辑,你也可以用不同的方式实现,比如在组合器的情况下,你可以有一个集合对象来拥有一个本地缓冲区,其中包含所有进入组合器的值,这比在 reducer 中使用风险要小,因为在 reducer 的情况下,它比在 combiner 中更容易耗尽内存。其他逻辑差异当然可以存在并且确实存在。

      【讨论】:

        【解决方案4】:

        是的,它们肯定会有所不同,但我不认为你想使用不同的类,因为大多数情况下你会得到意想不到的结果。

        Combiners 只能用于可交换(a.b = b.a) 和关联 {a.(b.c) = (a.b).c} 的函数。这也意味着组合器可能仅对您的键和值的子集进行操作,或者可能根本不执行,但您仍然希望程序的输出保持不变。

        选择具有不同逻辑的不同类可能不会给您带来逻辑输出。

        【讨论】:

          猜你喜欢
          • 2019-08-13
          • 1970-01-01
          • 2014-01-17
          • 2017-08-21
          • 2017-02-26
          • 1970-01-01
          • 2016-06-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多