web-dev-qa-db-ja.com

コンバイナーとレデューサーは異なる場合がありますか?

多くのMapReduceプログラムでは、レデューサーがコンバイナーとしても使用されています。私はこれがそれらのプログラムの特定の性質のためであることを知っています。しかし、私はそれらが異なる可能性があるかどうか疑問に思っています。

11
kee

はい、コンバイナーはレデューサーとは異なる場合がありますが、コンバイナーは引き続きレデューサーインターフェースを実装します。コンバイナーは、ジョブに依存する特定の場合にのみ使用できます。コンバイナーはレデューサーのように動作しますが、各マッパーから出力されるキー/値のサブセットに対してのみ機能します。

レデューサーとは異なり、コンバイナーが持つ1つの制約は、入力/出力キーと値のタイプ必須がマッパーの出力タイプと一致することです。

28
Binary Nerd

確かにそれらは異なる可能性がありますが、ほとんどの場合予期しない結果が得られるため、別のクラスを使用したくないと思います。

コンバイナは、可換(a.b = b.a)および結合法則{a。(b.c)=(a.b).c}の関数でのみ使用できます。これは、コンバイナーがキーと値のサブセットに対してのみ動作する場合や、まったく実行されない場合があることも意味します。それでも、プログラムの出力は同じままにしておきます。

異なるロジックで異なるクラスを選択すると、論理出力が得られない場合があります。

8
Animesh Raj Jha

これが実装です。コンバイナーなしとコンバイナーありで実行できます。どちらもまったく同じ答えを返します。ここで、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);
}
}

MapObjectクラス

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);
}
}

ここ からコードをGit

あなたの提案を残してください。

3
user3123372

コンバイナーの主な目標は、マッパーとリデューサーの間でネットワーク全体でシャッフルされるキーと値のペアの数を最適化/最小化して、可能な限り多くの帯域幅を節約することです。

コンバイナの経験則は、同じ入力変数タイプと出力変数タイプを持っている必要があるということです。この理由は、コンバイナの使用が保証されていないため、流出の量と数に応じて使用できる場合とできない場合があります。

レデューサーは、このルールを満たす場合、つまり同じ入力変数タイプと出力変数タイプの場合、コンバイナーとして使用できます。

コンバイナのもう1つの最も重要なルールは、適用する関数が可換で結合的である場合にのみ使用できることです。数字を足すようなものですが、平均的なものではありません(レデューサーと同じコードを使用している場合)。

今あなたの質問に答えるために、もちろんそれらは異なる可能性があります、そしてあなたのレデューサーが異なるタイプの入力と出力変数を持っているとき、uは選択の余地がありませんが、urレデューサーコードの異なるコピーを作成してそれを変更します。

レデューサーのロジックが心配な場合は、別の方法で実装することもできます。たとえば、コンバイナーの場合、コンバイナーに送られるすべての値のローカルバッファーを持つコレクションオブジェクトを作成できます。これは少なくなります。レデューサーの場合、コンバイナーよりもメモリが不足する傾向があるため、レデューサーで使用するよりもリスクが高くなります。他の論理的な違いは確かに存在する可能性があり、実際に存在します。

1
user3123372