分析

求出哪些人两两之间有共同好友,及他俩的共同好友都是谁

数据准备

  1. A:B,C,D,F,E,O
  2. B:A,C,E,K
  3. C:F,A,D,I
  4. D:A,E,F,L
  5. E:B,C,D,M,L
  6. F:A,B,C,D,E,O,M
  7. G:A,C,D,E,F
  8. H:A,C,D,E,O
  9. I:A,O
  10. J:B,O
  11. K:A,C,D
  12. L:D,E,F
  13. M:E,F,G
  14. O:A,H,I,J

共同好友 - 图1

分析下

  1. 比如前面是用户,后面是好友,那我们第一次就把好友开始统计,从冒号后面开始统计第一个输出:
  2. 把好友标在前面,用户放在后面(map阶段)
  3. b -a
  4. c -a
  5. d -a
  6. a -b
  7. c -b
  8. 然后把他们聚合,因为这样是有重复的(reduce阶段)
  9. 把第一个当做key,key相同的,其余的当做迭代的value
  10. 第一个输出:
  11. b -> a e j
  12. c ->a b e f h
  13. -------------------------
  14. 对上面的结果进行每行两两组合(map阶段)
  15. 后面的2个两两组合(注意写之前要排序)
  16. 不然a-bb-a会认为不同,map写的之前要排序下,都变成a-b
  17. 第二个MR:
  18. a-e b
  19. a-j b
  20. e-j b
  21. a-b c
  22. a-e c
  23. 然后把他们聚合(reduce阶段)
  24. 比如
  25. a-e b c d
  26. a-m e f

因为他是基于已经存在的单向好友关系的,反过来再找好友就是双向的
然后不断集合和排序,排序主要是防止A-B,B-A出现,两两组合

代码

第一步

  1. package com.Commonfriends;
  2. import com.index.IndexStepTwo;
  3. import org.apache.hadoop.conf.Configuration;
  4. import org.apache.hadoop.fs.FileSystem;
  5. import org.apache.hadoop.fs.Path;
  6. import org.apache.hadoop.io.LongWritable;
  7. import org.apache.hadoop.io.Text;
  8. import org.apache.hadoop.mapreduce.Job;
  9. import org.apache.hadoop.mapreduce.Mapper;
  10. import org.apache.hadoop.mapreduce.Reducer;
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  12. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
  13. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  14. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
  15. import java.io.IOException;
  16. public class CommonFriendsStepOne {
  17. public static class CommonFriendsStepOneMapper extends Mapper<LongWritable, Text, Text, Text> {
  18. //比如前面是用户,后面是好友,那我们第一次就把好友开始统计,从冒号后面开始统计第一个输出:
  19. //把好友标在前面,用户放在后面
  20. @Override
  21. protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
  22. String line = value.toString();
  23. String[] splits = line.split(":");
  24. String person = splits[0];
  25. String[] friends = splits[1].split(",");
  26. for (String fString : friends) {
  27. context.write(new Text(fString), new Text(person));
  28. }
  29. }
  30. }
  31. //然后把他们聚合
  32. public static class CommonFriendsStepOneReducer extends Reducer<Text, Text, Text, Text> {
  33. @Override
  34. protected void reduce(Text friend, Iterable<Text> person, Context context) throws IOException, InterruptedException {
  35. StringBuffer sBuffer = new StringBuffer();
  36. for (Text pText : person) {
  37. sBuffer.append(pText).append("-");
  38. }
  39. context.write(friend,new Text(sBuffer.toString()));
  40. }
  41. }
  42. public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
  43. Configuration conf = new Configuration();
  44. Job job = Job.getInstance();
  45. job.setJarByClass(CommonFriendsStepOne.class);
  46. //告诉程序,我们的程序所用的mapper类和reducer类是什么
  47. job.setMapperClass(CommonFriendsStepOneMapper.class);
  48. job.setReducerClass(CommonFriendsStepOneReducer.class);
  49. //告诉框架,我们程序输出的数据类型
  50. job.setMapOutputKeyClass(Text.class);
  51. job.setMapOutputValueClass(Text.class);
  52. job.setOutputKeyClass(Text.class);
  53. job.setOutputValueClass(Text.class);
  54. //告诉框架,我们程序使用的数据读取组件 结果输出所用的组件是什么
  55. //TextInputFormat是mapreduce程序中内置的一种读取数据组件 准确的说 叫做 读取文本文件的输入组件
  56. job.setInputFormatClass(TextInputFormat.class);
  57. job.setOutputFormatClass(TextOutputFormat.class);
  58. //告诉框架,我们要处理的数据文件在那个路劲下
  59. FileInputFormat.setInputPaths(job, new Path("/Users/jdxia/Desktop/website/hdfs/index/input/"));
  60. //如果有这个文件夹就删除
  61. Path out = new Path("/Users/jdxia/Desktop/website/hdfs/index/output/");
  62. FileSystem fileSystem = FileSystem.get(conf);
  63. if (fileSystem.exists(out)) {
  64. fileSystem.delete(out, true);
  65. }
  66. //告诉框架,我们的处理结果要输出到什么地方
  67. FileOutputFormat.setOutputPath(job, out);
  68. boolean res = job.waitForCompletion(true);
  69. System.exit(res ? 0 : 1);
  70. }
  71. }

第二步

其他要把第一步的结果,放到input下

  1. package com.Commonfriends;
  2. import org.apache.hadoop.conf.Configuration;
  3. import org.apache.hadoop.fs.FileSystem;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.LongWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapreduce.Job;
  8. import org.apache.hadoop.mapreduce.Mapper;
  9. import org.apache.hadoop.mapreduce.Reducer;
  10. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  11. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  13. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
  14. import java.io.IOException;
  15. import java.util.Arrays;
  16. public class CommonFriendsStepTwo {
  17. /**
  18. * A I-K-C-B-G-F-H-O-D-
  19. B A-F-J-E-
  20. C A-E-B-H-F-G-K-
  21. *
  22. */
  23. public static class CommonFriendsStepTwoMapper extends Mapper<LongWritable, Text, Text, Text> {
  24. @Override
  25. protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
  26. String line = value.toString();
  27. String[] splits = line.split(" ");
  28. String friend = splits[0];
  29. String[] persons = splits[1].split("-");
  30. Arrays.sort(persons);
  31. for (int i = 0; i < persons.length - 1; i++) {
  32. for (int j = i + 1; j < persons.length; j++) {
  33. context.write(new Text(persons[i] + "-" + persons[j]), new Text(friend));
  34. }
  35. }
  36. }
  37. }
  38. public static class CommonFriendsStepTwoReducer extends Reducer<Text,Text,Text,Text> {
  39. @Override
  40. protected void reduce(Text person_pair, Iterable<Text> friends, Context context) throws IOException, InterruptedException {
  41. StringBuffer sBuffer = new StringBuffer();
  42. for (Text fText: friends) {
  43. sBuffer.append(fText).append(" ");
  44. }
  45. context.write(person_pair, new Text(sBuffer.toString()));
  46. }
  47. }
  48. public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
  49. Configuration conf = new Configuration();
  50. Job job = Job.getInstance();
  51. job.setJarByClass(CommonFriendsStepTwo.class);
  52. //告诉程序,我们的程序所用的mapper类和reducer类是什么
  53. job.setMapperClass(CommonFriendsStepTwoMapper.class);
  54. job.setReducerClass(CommonFriendsStepTwoReducer.class);
  55. //告诉框架,我们程序输出的数据类型
  56. job.setMapOutputKeyClass(Text.class);
  57. job.setMapOutputValueClass(Text.class);
  58. job.setOutputKeyClass(Text.class);
  59. job.setOutputValueClass(Text.class);
  60. //告诉框架,我们程序使用的数据读取组件 结果输出所用的组件是什么
  61. //TextInputFormat是mapreduce程序中内置的一种读取数据组件 准确的说 叫做 读取文本文件的输入组件
  62. job.setInputFormatClass(TextInputFormat.class);
  63. job.setOutputFormatClass(TextOutputFormat.class);
  64. //告诉框架,我们要处理的数据文件在那个路径下
  65. FileInputFormat.setInputPaths(job, new Path("/Users/jdxia/Desktop/website/hdfs/index/input/"));
  66. //如果有这个文件夹就删除
  67. Path out = new Path("/Users/jdxia/Desktop/website/hdfs/index/output/");
  68. FileSystem fileSystem = FileSystem.get(conf);
  69. if (fileSystem.exists(out)) {
  70. fileSystem.delete(out, true);
  71. }
  72. //告诉框架,我们的处理结果要输出到什么地方
  73. FileOutputFormat.setOutputPath(job, out);
  74. boolean res = job.waitForCompletion(true);
  75. System.exit(res ? 0 : 1);
  76. }
  77. }