src=http___img.51miz.com_Element_00_58_87_70_1681ddfa_E588770_22d9a4cd.jpg&refer=http___img.51miz.webp

1.利用MapReduce进行数据挖掘

  1. 昨天的入门案例我们进行了利用MapReduce进行单词出现次数统计的案例,昨天是一个基础的统计案例,那么MapReduce也可以进行数据挖掘,今天展示一个经典案例(Child-Parent

2.准备工作

  1. 首先创建如下文本文件,并上传到HDFStest2文件夹中:
  1. Tom Lucy
  2. Tom Jack
  3. Jone Lucy
  4. Jone Jack
  5. Lucy Mary
  6. Lucy Ben
  7. Jack Alice
  8. Jack Jesse
  9. Terry Alice
  10. Terry Jesse
  11. Philip Terry
  12. Philip Alma
  13. Mark Terry
  14. Mark Alma

左侧为child,右侧为parent,我们要利用这些数据挖掘出GrandChild与GrandParent的关系

通过昨天的验视我们知道,MapReduce编写的三大核心:Map、Reduce、Job

ParentMapper.java

  1. import org.apache.hadoop.io.Text;
  2. import org.apache.hadoop.mapreduce.Mapper;
  3. import java.io.IOException;
  4. /**
  5. * @author
  6. */
  7. public class ParentMapper extends Mapper<Object,Text,Text,Text> {
  8. @Override
  9. protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
  10. //输出标识
  11. String temp;
  12. //读取行
  13. String line = value.toString();
  14. String words[] = line.split(" ");
  15. //输出左表
  16. temp = "1";
  17. context.write(new Text(words[1]),new Text(temp + "+" + words[0] + "+" + words[1]));
  18. //输出右表
  19. temp = "2";
  20. context.write(new Text(words[0]),new Text(temp + "+" + words[0] + "+" + words[1]));
  21. }
  22. }

ParentReducer.java

  1. import org.apache.hadoop.io.Text;
  2. import org.apache.hadoop.mapreduce.Reducer;
  3. import java.io.IOException;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. /**
  7. * @author
  8. */
  9. public class ParentReducer extends Reducer<Text,Text,Text,Text> {
  10. @Override
  11. protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
  12. List<String> grandChildList = new ArrayList<>();
  13. List<String> grandParentList = new ArrayList<>();
  14. for (Text value : values) {
  15. char temp = (char) value.charAt(0);
  16. String[] words = value.toString().split("[+]");
  17. if (temp == '1'){
  18. grandChildList.add(words[1]);
  19. }
  20. if (temp == '2'){
  21. grandParentList.add(words[2]);
  22. }
  23. }
  24. for (String grandChild : grandChildList) {
  25. for (String grandParent : grandParentList) {
  26. context.write(new Text(grandChild),new Text(grandParent));
  27. }
  28. }
  29. }
  30. }

ParentRunner.java

  1. import com.zym.mapper.ParentMapper;
  2. import com.zym.reducer.ParentReducer;
  3. import org.apache.hadoop.conf.Configuration;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.Text;
  6. import org.apache.hadoop.mapreduce.Job;
  7. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  8. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  9. import java.io.IOException;
  10. /**
  11. * @author
  12. */
  13. public class ParentRunner {
  14. public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
  15. Job job = Job.getInstance(new Configuration());
  16. job.setMapperClass(ParentMapper.class);
  17. job.setMapOutputKeyClass(Text.class);
  18. job.setOutputValueClass(Text.class);
  19. job.setReducerClass(ParentReducer.class);
  20. job.setOutputKeyClass(Text.class);
  21. job.setOutputValueClass(Text.class);
  22. FileInputFormat.addInputPath(job,new Path("hdfs://hadoop0:9000/test2"));
  23. FileOutputFormat.setOutputPath(job,new Path("hdfs://hadoop0:9000/output2"));
  24. boolean completion = job.waitForCompletion(true);
  25. if(completion){
  26. System.out.println("Job Success!");
  27. }
  28. }
  29. }

然后运行该main方法,查看结果:
1.png
分析:

  1. Map阶段,我们将孩子、父母的名字都作为key,整行数据作为value(行数据前面加12用来区分key是父辈还是子辈),然后交给Reduce
  2. Reduce阶段,我们读取到某个Map的键值对,拿到里面的value后,首先判断该value的首位是1还是2,如果是1则代表,该行数据中,这个key的名称是作为父辈出现的,所以将该行数据的第一个名称添加到grandChildList中;如果是2则代表,改行数据中,这个key的名称是作为子辈出现的,所以将该行数据的第二个名称添加到grandParentList中。然后我们对这两个集合进行笛卡尔积即可得到该key对应的祖父辈关系。
  3. 这里以Jack为例,在Map阶段结束后,数据应该是这样的:
  1. <"Jack",["1+Tom+Jack","1+Jone+Jack","2+Jack+Alice","2+Jack+Jesse"] >

所以Tom与Jone被放入了grandChildList中,而Alice与Jesse被放入了grandParentList中,他们之间的关系如图:
2.png
所以对于Tom与Jone来说,他们的祖父辈就是Alice与Jesse,当然对于其他的人来说也是一样的,都可以利用这种方法找到祖父辈与孙子辈的关系。通过这个案例我们更加深刻的理解了Map->Reduce的整个过程数据的变化。

总结:通过这样一个简单的案例不难看出,这样的数据挖掘还是很有必要的,尤其在大批量数据面前,靠人工计算显然是不现实的。自此,整个Hadoop我们可以说是已经入门了,那么接下来我们会继续学习Hadoop的其他组件来更加贴近与我们平时经常使用的框架与技术。