hadoop项目:社交粉丝,共同好友数据分析实现

日常开发中,MR解决问题思想:决定谁是k,相同的k会被发送到reduce中进行汇总
1.项目需求
以下是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
M:E,F,G
O:A,H,I,J
求出哪些人两两之间有共同好友,及他俩的共同好友都有谁?
2.分析
第一步
map
读一行   A:B,C,D,F,E,O
输出   
在读一行   B:A,C,E,K
输出  

REDUCE
拿到的数据比如......
算法:输出key相同的结果,比如都拥有C为粉丝的用户有哪些。
输出:
.....

第二步
map
读入一行
直接输出

reduce
读入数据  .......
输出: A-B  C,F,G,.....
项目拓展:求微博互粉的人

3.项目实现
用两个MR程序实现
  第一个MR实现输出每个粉丝有哪些人关注了
   public class SharedFriendsStepOne {
     //写了一个主类,其余都用静态内部类实现,当然也可以不用内部类。
    static class SharedFriendsStepOneMapper 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];
            String friends = person_friends[1];
       
            for (String friend : friends.split(",")) { //多次切割
                // 输出<好友,人>,以好友做k,一个人的所有好友分别做K,自己做v
                context.write(new Text(friend), new Text(person));
            }                  
        }
    }
   //reducer端,如果不用静态内部类,要重写一个class。这里为了演示,通用内部类实现。
    static class SharedFriendsStepOneReducer 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()));
        }
    }
 //Driver端实现。
    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();

        Job job = Job.getInstance(conf);
        job.setJarByClass(SharedFriendsStepOne.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        job.setMapperClass(SharedFriendsStepOneMapper.class);
        job.setReducerClass(SharedFriendsStepOneReducer.class);

        FileInputFormat.setInputPaths(job, new Path("D:/srcdata/friends"));   //当然这里可以用args[],控制台输入,更加了灵活多变
        FileOutputFormat.setOutputPath(job, new Path("D:/temp/out"));

        job.waitForCompletion(true);

    }
}
输出的结果 部分数据展示:  (默认kv的输出分隔符是\t)
A I,K,C,B,G,F,H,O,D,      //A后面的表示了哪些有A为好友粉丝的用户。这里没有排序。
B A,F,J,E,
C A,E,B,H,F,G,K     
第二次MR,用之前的结果
public class SharedFriendsStepTwo {

    static class SharedFriendsStepTwoMapper extends Mapper {
        // 拿到的数据是上一个步骤的输出结果
        // A I,K,C,B,G,F,H,O,D,
        // 友 人,人,人
        @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); //对persons进行排序,bc和 cb这样都是bc了。
                        //实现排列组合,即有A为好友的人任意两个都有共同好友,讲这些人排列组合。
            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));
                }

            }

        }

    }
     //第二次reducer端实现,对上面的输出进行聚合。即两个person_person的人有哪些好友,同K的v的。
    static class SharedFriendsStepTwoReducer 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 conf = new Configuration();
        Job job = Job.getInstance(conf);
        job.setJarByClass(SharedFriendsStepTwo.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        job.setMapperClass(SharedFriendsStepTwoMapper.class);
        job.setReducerClass(SharedFriendsStepTwoReducer.class);

        FileInputFormat.setInputPaths(job, new Path("D:/temp/out/part-r-00000"));
        FileOutputFormat.setOutputPath(job, new Path("D:/temp/out2"));

        job.waitForCompletion(true);
    }

}

最后输出部分结果: 
A---B E,C,
A---C D,F,
A---D E,F,
A---E D,B,C,
A---F O,B,C,D,E,
A---G F,E,C,D,
A---H E,C,D,O,
A---I         O,
A---J O,B,
A---K D,C,
A---L F,E,D,
A---M E,F,
B---C A,

你可能感兴趣的:(hadoop开发相关)