0. 项目结构
数据内容
刘灵薇 孙初丹,孙听兰,李秋翠,李绿春
王访琴 刘忆翠,钱语芙,钱平蝶
赵雅蕊 刘灵薇,刘雅蕊
王含蕾 钱语芙,李书蕾,李忆翠
钱雅蕊 李秋春,李初丹,孙听蓉
王绿春 李含烟,刘谷丝,孙秋春,钱雅蕊,赵语芙,钱南松,钱绿春,王听兰
刘含玉 赵绿春,王幻珊,刘语芙,赵怜菡,孙绿春,赵从蓉,赵南松,刘幻灵,王忆翠
钱凌瑶 孙诗云,王乐瑶,钱海露,孙从蓉
李含蕾 李从蓉,李从蓉,刘怜菡,钱灵雁
钱幻灵 赵书蕾,赵秋翠,刘幻珊,刘幻灵,刘雪青,钱夏彤,赵含蕾
刘夏彤 刘忆翠,钱诗云,王代曼,李雪青,赵白晴
刘初丹 李涵双,钱诗云,钱怜菡,孙含玉,李含烟,李听蓉,李海露,王涵双,钱凌瑶
李忆翠 钱秋翠,钱书蕾,孙灵薇,王夏彤,刘秋翠,赵从梦
王幻灵 孙幻灵,赵凌瑶,王语芙,刘灵薇,王代荷,王夏彤
孙忆翠 刘灵薇,赵涵双,刘夏彤,李雪青
李幻灵 赵凌瑶,王幻珊
王代曼 赵听白,王怜菡,孙南松,赵从梦,钱忆翠
刘代曼 李秋翠,赵听兰
刘绿春 王听白,赵书蕾,李怜菡,孙白晴,王怜菡,孙海露,赵南松
李听蓉 孙雅蕊,王含蕾
孙绿春 赵从蓉,王傲之,王听兰,赵诗云,李平蝶,孙听白,李忆翠,钱灵薇,王从蓉
王语芙 李听白,李幻灵,孙幻珊,李幻珊,孙秋春,赵谷丝,赵忆翠
王雪青 赵初丹,赵绿春,钱灵薇,赵从梦,王听白
赵访琴 赵访琴,王听白
孙谷丝 赵白晴,赵怜菡,孙秋春,钱幻灵
赵书蕾 李从蓉,王谷丝,赵乐瑶,李绿春,王绿春
刘语芙 王语芙,钱含烟,孙代荷,孙南松,王灵薇,赵雅蕊
孙乐瑶 李平蝶,刘听蓉,王凌瑶,钱绿春
王白晴 刘访琴,刘从梦,李海露
钱幻灵 李代荷,王听兰,赵听兰,刘傲之,王平蝶,钱幻珊,赵平蝶,孙白晴
钱涵双 刘秋翠,钱海露,赵含烟,刘幻珊
赵听蓉 刘初丹,王谷丝,赵幻灵,刘书蕾
孙雪青 钱凌瑶,赵海露,孙语芙
赵乐瑶 赵含烟,王书蕾,孙访琴,孙听兰,孙初丹,王涵双
赵海露 赵书蕾,孙听兰,王从蓉,刘听兰
钱幻灵 王含蕾,刘凌瑶,钱听兰,赵雅蕊,孙听兰,王秋春,李雅蕊,赵访琴,赵夏彤
李灵雁 钱乐瑶,孙平蝶,王代荷,刘雅蕊,刘平蝶,钱从梦,孙代曼,赵雪青
钱诗云 刘南松,刘代荷,李灵雁,李代曼,孙代荷,王秋翠,钱从蓉,钱秋春
赵含烟 刘访琴,孙谷丝,王幻灵,钱白晴,钱灵薇,王夏彤,王灵薇
李南松 刘南松,李夏彤,王语芙,赵秋翠
赵幻灵 刘语芙,李幻灵,孙傲之,钱灵薇,钱从蓉,刘听兰,李忆翠
钱含玉 钱灵薇,钱谷丝,赵代曼,李平蝶,王初丹,赵雪青
李书蕾 刘忆翠,王从蓉
李秋春 孙含玉,刘灵雁,刘绿春,赵秋翠
刘诗云 赵灵薇,刘平蝶,王听兰,赵书蕾,李秋春
刘听蓉 赵凌瑶,王从蓉,刘灵薇,王雅蕊,钱初丹,钱平蝶,孙初丹,李雪青
李白晴 孙绿春,孙含蕾
刘怜菡 刘谷丝,孙含蕾,钱书蕾,赵含蕾,李听蓉,孙灵薇,王海露
刘秋春 刘代荷,王听蓉,王含蕾,孙灵雁,李听蓉,赵代荷,钱绿春,刘忆翠,王忆翠
赵含蕾 孙白晴,孙凌瑶,李白晴,王雪青
孙雪青 王凌瑶,王从蓉
钱灵雁 钱含蕾,王含烟,李诗云,钱诗云,赵从蓉,刘平蝶,孙书蕾
刘代荷 王幻珊,钱雪青,王代曼,王含玉,孙平蝶
赵涵双 钱秋春,李从梦,赵听白,王访琴
刘书蕾 李傲之,孙乐瑶,赵怜菡,孙幻灵
赵幻灵 李凌瑶,李代曼,刘访琴,钱语芙
赵乐瑶 孙傲之,孙乐瑶
孙灵薇 孙代荷,赵访琴,孙绿春,钱乐瑶,刘代荷
刘夏彤 钱代曼,孙代荷,赵灵雁,钱书蕾,赵乐瑶,孙从蓉,刘访琴,孙灵雁
刘诗云 王从蓉,刘绿春,钱诗云,王从蓉,王白晴
李秋春 赵忆翠,刘雪青,刘幻珊,孙从梦,钱海露
思路
- 原数据格式:
用户 好友1,好友2,好友3....
- 好友对应的用户群: 我们的目标是处理出两两用户之间共同好友,而经过一个Map阶段后数据会被分为<key,value>的形式,而经过Reduce阶段相同的Key所对应的Value值将会合并。因此,可以从反向的思路出发,将好友作为Key,用户作为Value。使用MapReduce后,将会得到一个好友所对应的一群用户,即该好友为这群用户的共同好友。
数据格式:好友 用户1,用户2,用户3....
例如刘乐瑶 赵乐瑶,李绿春,钱听兰,赵访琴,李听兰,赵诗云,赵白晴 刘书蕾 钱怜菡,刘代荷,孙秋翠,李秋春,王南松
- 两两用户之间对应的共同好友: 再根据上述数据,我们要列出两两好友之间的好友,即目标数据格式为
用户1_用户2 好友1,好友2,好友3...
。
首先,将每个好友对应的用户数据进行处理,处理为用户1_用户2
这种格式。
(注意,先排序后处理。若未排序后处理,可能会出现相同的两个人,因次序不同而成为不同的Key,造成额外计数。在不同好友之间所对应的用户可能会出现这种形式张三_李四
和李四_张三
,会被认为是两种不同的数据,进行额外计数。)再倒回来处理数据,将用户作为Key,好友Value。经过Map阶段后,得到用户1_用户2 好友
这种形式的数据。最后经过Reduce阶段,将相同用户1 用户2
的Value值进行合并,得到两两好友之间的共同用户,形式为用户1_用户2 好友1,好友2,好友3
。
例如刘乐瑶_刘乐瑶 王含玉,赵傲之,赵夏彤,刘忆翠 刘乐瑶_刘书蕾 孙幻灵,赵夏彤,王从梦,刘含蕾,赵夏彤
1. Main
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {System.setProperty("HADOOP_USER_NAME", "root");Configuration conf = new Configuration();
// step1Job job1 = Job.getInstance(conf);job1.setJarByClass(FindFriend.class);job1.setMapperClass(FriendMapper.class);job1.setReducerClass(FriendReducer.class);job1.setOutputKeyClass(Text.class);job1.setOutputValueClass(Text.class);FileInputFormat.setInputPaths(job1,new Path("/hadoop_test/findFriend/friend.txt"));if( Utils_hadoop.testExist(conf,"/hadoop_test/findFriend/result")){Utils_hadoop.rmDir(conf,"/hadoop_test/findFriend/result");}FileOutputFormat.setOutputPath(job1, new Path("/hadoop_test/findFriend/result"));// true表示将运行进度等信息及时输出给用户,false的话只是等待作业结束boolean res1=job1.waitForCompletion(true);// step1Job job2 = Job.getInstance(conf);job2.setJarByClass(FindFriend.class);job2.setMapperClass(FriendMapper1.class);job2.setReducerClass(FriendReducer1.class);job2.setOutputKeyClass(Text.class);job2.setOutputValueClass(Text.class);FileInputFormat.setInputPaths(job2,new Path("/hadoop_test/findFriend/result"));if( Utils_hadoop.testExist(conf,"/hadoop_test/findFriend/result1")){Utils_hadoop.rmDir(conf,"/hadoop_test/findFriend/result1");}FileOutputFormat.setOutputPath(job2, new Path("/hadoop_test/findFriend/result1"));boolean res2 = job2.waitForCompletion(true);System.exit(res1?0:1);}
2. 处理好友对应的用户群MR
FriendMapper
class FriendMapper extends Mapper<LongWritable,Text, Text,Text>{@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {String line = value.toString();// 获取用户 uid孙诗云String uid = line.split("\t")[0];// 获取朋友 friends[钱白晴,李夏彤]String[] friends = line.split("\t")[1].split(",");for (String fre: friends) {// 钱白晴 孙诗云// 李夏彤 孙诗云// 钱白晴 李磊// 钱白晴 王芳// 输出格式: <朋友,用户>context.write(new Text(fre),new Text(uid));}}
}
FriendReducer
class FriendReducer extends Reducer<Text,Text,Text,Text>{@Overrideprotected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {StringBuilder sb = new StringBuilder(); // StringBuilder相当于是可以对其进行修改的Stringfor (Text uid: values) {sb.append(uid.toString()).append(",");}String re = sb.substring(0,sb.length()-1); // 转换成String形式// 朋友1 [用户1,用户2,用户3]// 钱白晴 [孙诗云,李磊,王芳 ] context.write(key,new Text(re));}
}
输出结果
好友 用户1,用户2,用户3...
刘乐瑶 赵乐瑶,李绿春,钱听兰,赵访琴,李听兰,赵诗云
刘书蕾 钱怜菡,刘代荷,孙秋翠,李秋春,王南松
刘含蕾 赵含玉,刘访琴,李雅蕊,刘幻珊,王南松
刘从蓉 钱听白,孙代荷,李平蝶,孙代荷,王傲之
2. 处理两两用户之间共同好友MR
FriendMapper1
class FriendMapper1 extends Mapper<LongWritable,Text, Text,Text>{@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {// 朋友1 用户1_用户2// 孙初丹 刘领会_李四_王五String line = value.toString();String[] lines= line.split("\t");//拿到朋友String fri = lines[0];//拿到用户String[] uid = lines[1].split(",");//先对用户进行一个排序,为后期防止出现相同两人因次序不同而带来的重复计算。例如:刘灵会_李四 李四_刘灵会
// [刘领会,李四,王五]Arrays.sort(uid);// 将所有用户都写成: 用户1_用户2 相同好友 这种形式// 从而输出两两用户之间的共同好友for (int i = 0; i <uid.length-1; i++) {for (int j = i+1; j <uid.length; j++) {context.write(new Text(uid[i]+"_"+uid[j]),new Text(fri));}}}
}
FriendReducer1
class FriendReducer1 extends Reducer<Text,Text,Text,Text>{// 刘能_赵四 孙诗云// 刘能_赵四 李磊// 刘能_赵四 王芳@Overrideprotected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {StringBuilder sb = new StringBuilder();// 将两两用户之间的共同好友合并处理后输出for (Text fre:values) {sb.append(fre+",");}String re = sb.substring(0,sb.length()-1);// 刘能_赵四 [孙诗云,李磊,王芳]context.write(new Text(key),new Text(re));}
}
输出结果
用户1_用户2 好友1,好友2,好友3...
刘乐瑶_刘乐瑶 王含玉,赵傲之,赵夏彤,刘忆翠
刘乐瑶_刘书蕾 孙幻灵,赵夏彤,王从梦,刘含蕾,赵夏彤
刘乐瑶_刘从梦 李雪青,刘绿春,孙南松,钱绿春
刘乐瑶_刘从蓉 钱白晴,刘含玉,刘夏彤,刘绿春,钱绿春,刘含蕾,李平蝶,钱幻珊,赵含蕾,刘夏彤
刘乐瑶_刘代曼 李平蝶,李秋翠,王秋翠