MapReduce求共同好友

题目:以下是qq的好友列表数据,冒号前是一个用户,冒号后是该用户的所有好友(数据中的好友关系是单向的)

A:B,C,D,F,E,O
B:A,C,E,K
C:F,A,D,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
H:E,F,G
O:A,H,I,J
P:H,L,S,F,E,A,C,D

求出哪些人两两之间有共同好友,及他俩的共同好友都有谁?
解题思路:
第一步:先找出一个用户是哪些用户的共同好友(比如C是哪些用户的共同好友,以上题目中的C是用户A,B,E,F,G,H,K的共同好友,所以AB的共同好友为C,AE的共同好友为C,以此类推。。。)

第二步:经过第一步推算,得到AE的 共同好友还有D,最后将AE的共同好友合并得到C,D,这只是举个例子,他们的共同好友还有很多,即将两两用户作为key,好友作为value,以此类推,因此需要写两个mapreduce。

代码实现

第一个mapreduce
public class IdenticalFriendsStepOne {

public static void main(String[] args) throws Exception {
    // TODO Auto-generated method stub
    Configuration configuration = new Configuration();
    
    Job job = Job.getInstance(configuration);
    //指定本程序的jar包所在的本地路径
    job.setJarByClass(IdenticalFriendsStepOne.class);
    
    job.setMapperClass(IdenticalFriendsStepOneMapper.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(Text.class);
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    
    job.setReducerClass(IdenticalFriendsStepOneReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
    job.waitForCompletion(true);

}

public static class IdenticalFriendsStepOneMapper extends Mapper{

    
    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        //A:B,C,D,F,E,O
        //获取文本一行数据,转化为字符串
        String line = value.toString();
        //将字符串以 :号分割,转换成数组 
        String[] person_friends = line.split(":");
        
        //数组的第一个值为用户
        String person = person_friends[0];
        
        //数组的第二个值为用户的好友,即B,C,D,F,E,O
        String friends = person_friends[1];
        
        //将用户的好友遍历出来
        for(String friend : friends.split(",")) {
            
            //输出<好友,用户>
            context.write(new Text(friend), new Text(person));
        }
    }
    
}

public static class IdenticalFriendsStepOneReducer extends Reducer{

    @Override
    protected void reduce(Text friend, Iterable persons, Context context)
            throws IOException, InterruptedException {
        StringBuffer sb = new StringBuffer();
        
        for(Text person : persons) {
            
            sb.append(person).append(",");
        }
        context.write(friend, new Text(sb.toString()));
    }   
  }
}

结果输出

A   H,I,B,C,D,F,O,G,P,K,
B   J,F,A,E,
C   P,H,F,A,K,B,G,E,
D   P,L,K,H,F,E,C,A,G,
E   P,D,G,H,H,B,F,A,L,
F   D,L,H,A,C,P,G,
G   H,
H   P,O,
I   O,C,
J   O,
K   B,
L   D,E,P,
M   F,E,
O   J,H,A,I,F,
S   P,

为了防止b–>c和c–>b这样同一对朋友的重复,所以,下面基于这个结果处理的时候,需要进行排序,这样就能达到没有重复朋友对的出现。

第二个mapreduce

public class IdenticalFriendsStepTwo {

public static class IdenticalFriendsStepTwoMapper extends Mapper {

    //拿到的数据是上一个步骤的输出结果
    //A H,I,B,C,D,F,O,G,P,K,(即A是H,I,B,C,D,F,O,G,P,K这些用户的好友)
    //友  人,人,人
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

        String line = value.toString();
        String[] friend_persons = line.split("\t");

        String friend = friend_persons[0];
        String[] persons = friend_persons[1].split(",");

        Arrays.sort(persons);

        for (int i = 0; i < persons.length - 1; i++) {
            for (int j = i + 1; j < persons.length; j++) {
                // 发出 <人-人,好友> ,这样,相同的“人-人”对的所有好友就会到同1个reduce中去
                context.write(new Text(persons[i] + "-" + persons[j]), new Text(friend));
            }

        }

    }

}

public static class IdenticalFriendsStepTwoReducer extends Reducer {

    @Override
    protected void reduce(Text person_person, Iterable friends, Context context) throws IOException, InterruptedException {

        StringBuffer sb = new StringBuffer();

        for (Text friend : friends) {
            sb.append(friend).append(" ");

        }
        context.write(person_person, new Text(sb.toString()));
    }

}

public static void main(String[] args) throws Exception {

    Configuration configuration = new Configuration();
    
    Job job = Job.getInstance(configuration);
    job.setJarByClass(IdenticalFriendsStepTwo.class);
    
    job.setMapperClass(IdenticalFriendsStepTwoMapper.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(Text.class);
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    
    //job.setReducerClass(IdenticalFriendsStepTwoReducer.class);
    
    job.setReducerClass(IdenticalFriendsStepTwoReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
    job.waitForCompletion(true);

  }

}

输出结果

A-B E C 
A-C D F 
A-D E F 
A-E B D C 
A-F E O B C D 
A-G E C D F 
A-H D E O F E C 
A-I O 
A-J B O 
A-K D C 
A-L D F E 
A-P F D E C 
B-C A 
B-D E A 
B-E C 
B-F A C E 
B-G C E A 
B-H E A C E 
B-I A 
B-K C A 
B-L E 
B-O A 
B-P A E C 
C-D A F 
C-E D 
C-F D A 
C-G F D A 
C-H F A D 
C-I A 
C-K D A 
C-L F D 
C-O A I 
C-P D F A 
D-E L 
D-F E A 
D-G A F E 
D-H F E E A 
D-I A 
D-K A 
D-L E F 
D-O A 
D-P A L F E 
E-F M D C B 
E-G C D 
E-H C D 
E-J B 
E-K C D 
E-L D 
E-P D L C 
F-G A D C E 
F-H E A C E O D 
F-I A O 
F-J O B 
F-K A D C 
F-L E D 
F-O A 
F-P A E C D 
G-H D E E C A F 
G-I A 
G-K A C D 
G-L E D F 
G-O A 
G-P F E C A D 
H-H E 
H-I A O 
H-J O 
H-K D C A 
H-L F E D E 
H-O A 
H-P F A E C D E 
I-J O 
I-K A 
I-O A 
I-P A 
K-L D 
K-O A 
K-P C D A 
L-P E F D 
O-P A H

你可能感兴趣的:(MapReduce求共同好友)