在MapReduce中连接具有多个值的两个数据集

时间:2014-11-28 13:58:00

标签: hadoop join mapreduce

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

电影的元数据

975900  /m/03vyhn   Ghosts of Mars  2001-08-24  14010832    98.0    {"/m/02h40lc": "English Language"}  {"/m/09c7w0": "United States of America"}   {"/m/01jfsb": "Thriller", "/m/06n90": "Science Fiction", "/m/03npn": "Horror", "/m/03k9fj": "Adventure", "/m/0fdjb": "Supernatural", "/m/02kdv5l": "Action", "/m/09zvmj": "Space western"}
3196793 /m/08yl5d   Getting Away with Murder: The JonBenét Ramsey Mystery   2000-02-16      95.0    {"/m/02h40lc": "English Language"}  {"/m/09c7w0": "United States of America"}   {"/m/02n4kr": "Mystery", "/m/03bxz7": "Biographical film", "/m/07s9rl0": "Drama", "/m/0hj3n01": "Crime Drama"}
28463795    /m/0crgdbh  Brun bitter 1988        83.0    {"/m/05f_3": "Norwegian Language"}  {"/m/05b4w": "Norway"}  {"/m/0lsxr": "Crime Fiction", "/m/07s9rl0": "Drama"}
9363483 /m/0285_cd  White Of The Eye    1987        110.0   {"/m/02h40lc": "English Language"}  {"/m/07ssc": "United Kingdom"}  {"/m/01jfsb": "Thriller", "/m/0glj9q": "Erotic thriller", "/m/09blyk": "Psychological thriller"}

字符的元数据

975900  /m/03vyhn   2001-08-24  Akooshay    1958-08-26  F   1.62        Wanda De Jesus  42  /m/0bgchxw  /m/0bgcj3x  /m/03wcfv7
975900  /m/03vyhn   2001-08-24  Lieutenant Melanie Ballard  1974-08-15  F   1.78    /m/044038p  Natasha Henstridge  27  /m/0jys3m   /m/0bgchn4  /m/0346l4
975900  /m/03vyhn   2001-08-24  Desolation Williams 1969-06-15  M   1.727   /m/0x67 Ice Cube    32  /m/0jys3g   /m/0bgchn_  /m/01vw26l
975900  /m/03vyhn   2001-08-24  Sgt Jericho Butler  1967-09-12  M   1.75        Jason Statham   33  /m/02vchl6  /m/0bgchnq  /m/034hyc

在第一个文件中,我对第一个字段感兴趣,第一个字段是电影ID和第三个字段电影名称。在第二个文件中,第一个字段是电影ID,第9个字段是演员姓名。每个movieId可以有多个actor名称,如上面的file-2所示。我想要实现的输出采用以下格式

movieId     movieName, actorName1, actorName2, actorName3....etc.

我成功地从两个映射器类中提取字段。在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));
}
}
}

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

2 个答案:

答案 0 :(得分:0)

即使您的代码遍历所有值,它似乎也不会累积演员名称,而是保持用新的名称覆盖当前演员名称。
而不是:

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

试试这个:

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

答案 1 :(得分:-1)

嗨〜我刚看完你的代码。我和Gwen有同样的建议。如果您希望结果记录为&#34;电影ID&#34; +&#34;电影名称&#34; +&#34;演员&#34;。您必须同时将所有输出值放入context.write()。所以Gwen建议的是你必须做的事情。

我认为失败的工作不是Mapreduce问题,而是HDFS问题。查看&#34; Hadoop: File … could only be replicated to 0 nodes, instead of 1&#34;。

我很好奇的是JoinMap2部分。

String values[] = line.toString().split("\t");
movieId = values[0].trim();
actorName = values[8].trim().replaceAll("\t", "actor Name");

您将 与&#34; \ t&#34;分开,这意味着必须没有&#34; \ t&#34;在 values [] 的任何单元格内部。

所以你真的希望它在第3行吗?替换&#34; \ t&#34;到&#34;演员姓名&#34;?没有&#34; \ t&#34;在 值[8]

至少需要做三件事才能完成MapReduce工作。

  1. 修复您的HDFS。
  2. 重写JoinMap2以确保它输出您想要的答案。演员。
  3. 重写减速机,就像Gwen说的那样。