使用Map Reduce

时间:2017-09-20 05:28:28

标签: java hadoop mapreduce

加入2个文件的内容:

第一个文件(包含员工姓名数据)

id,name
101,Gaurav
102,Rohit
103,Karishma
104,Darshan
105,Divya

第二个文件(包含员工部门数据)

id,dept
101,Sales
102,Research
103,NMG
104,Admin
105,HR

==========================

输出

id,name,dept
101,Gaurav,Sales
102,Rohit,Research
103,Karishma,NMG

我如何实现这种输出?

到目前为止,我在减速器中将其作为随机值,如..

我想按照指定的顺序输出输出,例如id,name,department。 任何帮助表示赞赏。

Mapper类看起来像这样......

public class JoinMapper extends Mapper<LongWritable, Text, Text, Text> {
private Text keyEmit = new Text();
private Text valEmit = new Text();
public void map(LongWritable k, Text value, Context context) throws IOException, InterruptedException
{
 String line=value.toString();
 String[] words=line.split(",");
 keyEmit.set(words[0]);
 valEmit.set(words[1]);
 context.write(keyEmit, valEmit);
}
}

Reducer类看起来像这样......

public class JoinReducer extends Reducer<Text, Text, NullWritable, Text> {
String merge = "";
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
    merge = key.toString(); // 101
    for(Text value : values) {
        merge +=  "," + value.toString();
    }
    context.write(NullWritable.get(), new Text(merge));
}
}

驱动程序类看起来像这样......

public class JoinDriver {
public final static void main(final String[] args) throws Exception {
    Configuration conf = new Configuration();
    Job job = new Job(conf, "Multiple join");

    job.setJarByClass(JoinDriver.class);
    // job.setMapperClass(JoinMapper.class);
    job.setReducerClass(JoinReducer.class);

    MultipleInputs.addInputPath(job, new Path(args[0]),
            TextInputFormat.class, JoinMapper.class);

    MultipleInputs.addInputPath(job, new Path(args[1]),
            TextInputFormat.class, JoinMapper.class);

    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(Text.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);
    job.setOutputFormatClass(TextOutputFormat.class);
    FileOutputFormat.setOutputPath(job, new Path(args[2]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}

截至目前,输出如下,我希望它本身就像id,name,department一样。

output as of now

1 个答案:

答案 0 :(得分:0)

你遇到的主要问题是值没有排序,因此你要对一个公共密钥进行分组,但只是将这些值作为字符串发送并不是很有帮助,因为你不知道哪个是名字,哪个是部门

您有几个选项,所有这些选项都需要从映射器发送更多信息:

  1. 使用辅助排序
  2. 对reducer中的值进行排序
  3. 最快的方法是在映射器中输出更多信息时(理想情况下,您实际上会使用包含两个Text对象的复合值)。

    public class JoinMapperName extends Mapper<LongWritable, Text, Text, Text> {
        public void map(LongWritable k, Text value, Context context) 
                              throws IOException, InterruptedException {
    
            String[] words = value.toString().split(",");
            context.write(new Text(words[0]), new Text("name:" + words[1]));
        }
    }
    
    public class JoinMapperDept extends Mapper<LongWritable, Text, Text, Text> {
        public void map(LongWritable k, Text value, Context context) 
                              throws IOException, InterruptedException {
    
            String[] words = value.toString().split(",");
            context.write(new Text(words[0]), new Text("dept:" + words[1]));
        }
    }
    

    所以现在每个数据源都有一个不同的映射器。您需要将减速器更改为:

    public class JoinReducer extends Reducer<Text, Text, NullWritable, Text> {
        public void reduce(Text key, Iterable<Text> values, Context context) 
                  throws IOException, InterruptedException {
    
            String name = "";
            String dept = "";
            for(Text value : values) {
                if (value.toString().startsWith("name")) {
                    name = value.toString().split(":")[1];
                } else {
                    dept = value.toString().split(":")[1];
                }
            }
            String merge = key + "," name + "," + dept;
            context.write(NullWritable.get(), new Text(merge));
        }
    }
    

    这只是一个关于如何做到这一点的简单示例。希望它能为您提供有关如何强制执行订购的一些想法。