设计和实现基于Map-Reduce框架的家族图谱算法
1、核心算法(只有一个类,并且有大量注释)
package com.ss.test;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration config = new Configuration();
config.set("fs.defaultFS", "hdfs://192.168.43.128:9000");
config.set("yarn.resourcemanager.hostname", "192.168.43.128");
FileSystem fs = FileSystem.get(config);
Job job = Job.getInstance(config);
job.setJarByClass(Test.class);
// 设置所用到的map类
job.setMapperClass(myMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
// 设置用到的reducer类
job.setReducerClass(myReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
// 设置输入输出地址
FileInputFormat.addInputPath(job, new Path("/15200141115/input/Test.txt"));
Path path = new Path("/15200141115/output2/");
if (fs.exists(path)) {
fs.delete(path, true);
}
// 指定文件的输出地址
FileOutputFormat.setOutputPath(job, path);
// 启动处理任务job
boolean completion = job.waitForCompletion(true);
if (completion) {
System.out.println("执行成功!");
}
}
// map过程,按行读入,每行都会执行一次map函数,以split分割,按以下规则输出map键值对,找准key是关键
public static class myMapper extends Mapper<Object, Text, Text, Text> {
// 实现map函数
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
String temp = new String();// 用来标识关系
// 如tom(子女),lucy(父母),可转化为以当前父母为key的map (lucy,1Tom),表示为tom是lucy的孩子
// 再取lucy(子女),mary(父母v), 可转化为以当前子女为key的map
// (lucy,2mary),表示为lucy是mery的孩子
// 这样做有什么好处?使得在shuffle的过程中,自动转化为(lucy,[1tom,2mery]),使得tom(孙子)与mery(爷奶)联系在一起了
// shuffle过程,系统自动完成,不需要写函数。它的作用是使得相同key的键值对,转化为新的键值对,键依然为之前的key,
// value为之前所有vaue的集合,即values
// 举个例子 map后形成(lucy,1tom) (lucy,2mery) shuffle后 形成 (lucy
// ,[1tom,2mery])
String values = value.toString();
String words[] = values.split(" ");
// Tom Lucy
temp = "1";
context.write(new Text(words[1]), new Text(temp + words[0]));
// (Lucy,1Tom)
// 表示Tom为Lucy的子女
temp = "2";
context.write(new Text(words[0]), new Text(temp + words[1]));
// (Tom,2Lucy)
// 表示Lucy为Tom的父母
}
}
// reduce过程,将shuffle后形成的数据value数组进行处理,
// 有多少不同的key,那么调用reduce多少次
// 比如wordcount里就是遍历values,求和,即由(hello,[1,1])变成(hello,2)
public static class myReducer extends Reducer<Text, Text, Text, Text> {
// 实现reducer函数
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
List<String> grandchild = new ArrayList<String>();
List<String> grandparent = new ArrayList<String>();
// 遍历values数组
// 比如当前key为lucy,则此时values为[1tom,2lucy]
for (Text value : values) {
// 获取关系标识符
// 即1tom 取1
char temp = (char) value.charAt(0);
// 获取标识符右面的节点
// 即1tom 取tom
String right = value.toString().substring(1, value.getLength());
// 等于1时,说明右方节点是key的孩子,即(lucy,1tom) tom是lucy的孩子
// 那么把当前孩子加入到孙子list中
if (temp == '1') {
grandchild.add(right);
}
// 等于2时,说明右方节点是key的父母,即(lucy,2mery)mery是lucy的父母
// 那么把当前父母加入到爷奶list中
if (temp == '2') {
grandparent.add(right);
}
}
// 求笛卡尔儿积
// 比如此时孙子有{tom,jone}
// 爷奶有{lucy,jack}
// 则输出为(tom,lucy) (tom,jack) (jone,lucy) (jone,jack)
// 也就是笛卡儿积的结果
for (String gc : grandchild) {
for (String gp : grandparent) {
context.write(new Text(gc), new Text(gp));
}
}
}
}
}
2、选择测试文本
Tom Lucy
Tom Jack
Jone Lucy
Jone Jack
Lucy Mary
Lucy Ben
Jack Alice
Jack Jesse
Terry Alice
Terry Jesse
Philip Terry
Philip Alma
Mark Terry
Mark Alma
3、运行结果
可见算法是正确的