【Mapreduce】利用单表关联在父子关系中求解爷孙关系

首先是有如下数据,设定左边是右边的儿子,右边是左边的父母

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
要求输出如下所示的爷孙关系,左边是右边的孙子,右边是左边的祖父母:

Tom	Jesse
Tom	Alice
Jone	Jesse
Jone	Alice
Jone	Ben
Jone	Mary
Tom	Ben
Tom	Mary
Philip	Alice
Philip	Jesse
Mark	Alice
Mark	Jesse

要利用Mapreduce解决这个问题,主要思想如下:

1、在Map阶段,将父子关系与相反的子父关系,同时在各个value前补上前缀-与+标识此key-value中的value是正序还是逆序产生的,之后进入context。

下图通过其中的Jone-Lucy Lucy-Mary,求解出Jone-Mary来举例


2、MapReduce会自动将同一个key的不同的value值,组合在一起,推到Reduce阶段。在value数组中,跟住前缀,我们可以轻松得知,哪个是爷,哪个是孙。

因此对各个values数组中各个项的前缀进行输出。


可以看得出,整个过程Key一直被作为连接的桥梁来用。形成一个单表关联的运算。


因此代码如下,根据上面的思想很容易得出如下的代码了,需要注意的是,输出流输入流都要设置成Text,因为全程都是在对Text而不是IntWritable进行操作:

import java.io.IOException;
import java.util.ArrayList;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class MyMapReduce {

	public static class MyMapper extends Mapper<Object, Text, Text, Text> {

		public void map(Object key, Text value, Context context)
				throws IOException, InterruptedException {
			String child = value.toString().split(" ")[0];
			String parent = value.toString().split(" ")[1];
			//产生正序与逆序的key-value同时压入context
			context.write(new Text(child), new Text("-" + parent));
			context.write(new Text(parent), new Text("+" + child));
		}
	}

	public static class MyReducer extends Reducer<Text, Text, Text, Text> {

		public void reduce(Text key, Iterable<Text> values, Context context)
				throws IOException, InterruptedException {
			ArrayList<Text> grandparent = new ArrayList<Text>();
			ArrayList<Text> grandchild = new ArrayList<Text>();
			for (Text t : values) {//对各个values中的值进行处理
				String s = t.toString();
				if (s.startsWith("-")) {
					grandparent.add(new Text(s.substring(1)));
				} else {
					grandchild.add(new Text(s.substring(1)));
				}
			}
			//再将grandparent与grandchild中的东西,一一对应输出。
			for (int i = 0; i < grandchild.size(); i++) {
				for (int j = 0; j < grandparent.size(); j++) {
					context.write(grandchild.get(i), grandparent.get(j));
				}
			}
		}
	}

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();

		String[] otherArgs = new GenericOptionsParser(conf, args)
				.getRemainingArgs();
		if (otherArgs.length != 2) {
			System.err.println("Usage: wordcount <in> <out>");
			System.exit(2);
		}
		Job job = new Job(conf);
		job.setMapperClass(MyMapper.class);
		job.setReducerClass(MyReducer.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);

		// 判断output文件夹是否存在,如果存在则删除
		Path path = new Path(otherArgs[1]);// 取第1个表示输出目录参数(第0个参数是输入目录)
		FileSystem fileSystem = path.getFileSystem(conf);// 根据path找到这个文件
		if (fileSystem.exists(path)) {
			fileSystem.delete(path, true);// true的意思是,就算output有东西,也一带删除
		}

		FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
		FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
		System.exit(job.waitForCompletion(true) ? 0 : 1);
	}

}


  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值