Hadoop 在MapReduce中使用多个值连接两个数据集

Hadoop 在MapReduce中使用多个值连接两个数据集,hadoop,join,mapreduce,Hadoop,Join,Mapreduce,我一直在尝试连接两个数据集的字段,但都没有成功。如果有人能帮我做到这一点,我将不胜感激。我一直在尝试的文件和代码如下 电影元数据 字符元数据 在第一个文件中,我对第一个字段感兴趣,它是电影id和第三个字段电影名称。而在第二个文件中,第一个字段是电影id,第九个字段是演员姓名。每个电影ID可以有多个演员名称,如上面的文件2所示。我试图实现的输出格式如下 movieId movieName, actorName1, actorName2, actorName3....etc. 我已经成功地

我一直在尝试连接两个数据集的字段,但都没有成功。如果有人能帮我做到这一点,我将不胜感激。我一直在尝试的文件和代码如下

电影元数据

字符元数据

在第一个文件中,我对第一个字段感兴趣,它是电影id和第三个字段电影名称。而在第二个文件中,第一个字段是电影id,第九个字段是演员姓名。每个电影ID可以有多个演员名称,如上面的文件2所示。我试图实现的输出格式如下

movieId     movieName, actorName1, actorName2, actorName3....etc.
我已经成功地从两个mapper类中提取了字段。在reducer类中,我的代码似乎没有达到我想要作为输出的上述格式。我得到的输出是

movieId movieName, actorName1
我不知道其他演员的名字。请看一下我的代码,并相应地更正我

public class Join {
    public static void main(String[] args) throws Exception {
        if (args.length != 3) {
            System.err.println("Usage: Join <input path> <output path>");
            System.exit(-1);
        }

    Configuration conf = new Configuration();
    Job job = Job.getInstance(conf);
    job.setJobName("Join");

    job.setJarByClass(Join.class);
    job.setReducerClass(JoinReduce.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);

    MultipleInputs.addInputPath(job, new Path(args[0]),
             TextInputFormat.class, JoinMap1.class);
             MultipleInputs.addInputPath(job, new Path(args[1]),
             TextInputFormat.class, JoinMap2.class);
    FileOutputFormat.setOutputPath(job, new Path(args[2]));

    System.exit(job.waitForCompletion(true) ? 0 : 1);
}

public static class JoinMap1 extends
        Mapper<LongWritable, Text, Text, Text> {
    private String movieId, movieName, fileTag = "A~ ";

    @Override
    public void map(LongWritable key, Text value,Context context) 
            throws IOException, InterruptedException {
        String values[] = value.toString().split("\t");
        movieId = values[0].trim();
        movieName = values[2].trim().replaceAll("\t", "movie Name");
        context.write(new Text(movieId), new Text (fileTag + movieName));
    }

}

public static class JoinMap2 extends Mapper<LongWritable, Text, Text, Text>{
    private String movieId, actorName, fileTag = "B~ ";
    @Override
    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();
        String values[] = line.toString().split("\t");
        movieId = values[0].trim();
        actorName = values[8].trim().replaceAll("\t", "actor Name");
        context.write(new Text (movieId), new Text (fileTag + actorName));
    }
}

public static class JoinReduce extends
        Reducer<Text, Text, Text, Text> {
     private String movieName, actorName;
    @Override
    public void reduce(Text key, Iterable<Text> values, Context context) 
            throws IOException, InterruptedException 
    { 
        for (Text value : values){
            String currValue = value.toString();
            String splitVals[] = currValue.split("~");
            if(splitVals[0].equals("A")){
                movieName = splitVals[1] != null ? splitVals[1].trim() : "movieName";
            } else if (splitVals[0].equals("B")){
                actorName= splitVals[1] != null ? splitVals[1].trim() : "actorName";
            }  
        }
        context.write(key, new Text (movieName + ", " + actorName));
}
}
}

请建议我可以做什么,以便我可以实现上述输出。任何帮助都将不胜感激。砖块和蝙蝠是受欢迎的。

即使您的代码对所有值进行迭代,它似乎不会累积参与者名称,而是不断用新名称覆盖当前参与者名称。 与此相反:

actorName= splitVals[1] != null ? splitVals[1].trim() : "actorName";
试试这个:

actorName += splitVals[1] != null ? splitVals[1].trim() : "actorName" + ",";

嗨~我刚读了你的密码。我有和格温一样的建议。如果希望结果记录包含电影ID+电影名称+演员。必须同时将所有输出值放入context.write。所以格温建议的是你必须做的

我认为作业失败不是Mapreduce问题,而是HDFS问题。退房

我很好奇的一件事是JoinMap2部分

String values[] = line.toString().split("\t");
movieId = values[0].trim();
actorName = values[8].trim().replaceAll("\t", "actor Name");
您使用\t拆分该行,因此这意味着任何值为[]的单元格内都不能有\t

那么你真的想在第三条线上做吗?是否将\t替换为参与者名称?值[8]中没有\t

要完成MapReduce工作,您至少需要做三件事

修复您的HDF。 重写JoinMap2以确保它输出您想要的答案。演员们。 正如格温所说,重写reducer。
您好,Gwen,我按照建议对代码进行了更改,但MapReduce作业未能抛出错误文件/user/uzair/output/joinout/_temporary/_trunt\u 201411290045\u 0001\u r\u000000\u 1/part-r-00000只能复制到0个节点,而不是1个节点。如果未对代码进行任何更改,作业将成功运行。当作业按照建议进行更改运行时,我检查了_temporary/_trunt_201411290045_0001_r_000000_1/part-r-00000,其中每个记录都有movieId、movieName,但对于actorNames,所有记录中的所有actorNames,不管键是什么,都会被追加。谢谢你的回复。当我测试其他东西时,我在上面引用的代码u jst中放了第三行。我把它全部删除了。只有当我按照Gwen的建议更改reducer代码时,我才得到HDFS问题。HDFS没有问题。实际发生的情况是,类似键r的所有值都没有被视为相同的键。例如,key:movieId 0001的值:movieName SomeMovie&相同的键:movieId 0001的值:actorName SomeActor r被视为不同的键。如果我不能表达,我很抱歉。如果你不明白我刚才说的话,我可以更新我得到的代码和输出。
actorName += splitVals[1] != null ? splitVals[1].trim() : "actorName" + ",";
String values[] = line.toString().split("\t");
movieId = values[0].trim();
actorName = values[8].trim().replaceAll("\t", "actor Name");