MapReduce处理表的自连接

原始数据

/*
 * 原始数据
 * 子    父
 * Tom Lucy
 Tom Jack
 Jone Locy
 Jone Jack
 Lucy Mary
 Lucy Ben
 Jack Alice
 Jack Jesse
 TerryAlice
 TerryJesse
 PhilipAlma
 Mark Terry
 Mark Alma
 */

要求通过子父关系找出子-祖母关系

/*
 * 设计方法:连接的左表的parent列(key),右表的child列(key),且左右表属于同一张表
 * 所以在map阶段将读入数据分割成child,parent后,会将parent设置成key,child设置成value输出,并作为左表
 * 再将同一对child和parent中的child作为key,parent作为value进行输出,作为右表
 * 为了区分输出中的左右表,需要在输出的value中再加上左右表的信息,比如在value的string最开始出加上字符1表示左表,加上2表示右表。
 * 然后在shuffle过程中完成连接,reduce接收到连接的结果,其中每个key的value-list就包含了“grandchild-grandparent”关系。
 * 取出每个key的value-list进行解析,将左表中的child放入一个数组(就一个key),右表中的grandparent放入一个数组,然后对两个数组求笛卡儿积就ko了
 *
 */

1.Map类

package test.mr.selfrelated;

import java.io.IOException;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

/*
 * 表的自连结(grandchild-grandparend表)
 */
/*
 * 原始数据
 * 子    父
 * Tom	Lucy
 Tom	Jack
 Jone	Locy
 Jone	Jack
 Lucy	Mary
 Lucy	Ben
 Jack	Alice
 Jack	Jesse
 TerryAlice
 TerryJesse
 PhilipAlma
 Mark	Terry
 Mark	Alma
 */
/*
 * 设计方法:连接的左表的parent列(key),右表的child列(key),且左右表属于同一张表
 * 所以在map阶段将读入数据分割成child,parent后,会将parent设置成key,child设置成value输出,并作为左表
 * 再将同一对child和parent中的child作为key,parent作为value进行输出,作为右表
 * 为了区分输出中的左右表,需要在输出的value中再加上左右表的信息,比如在value的string最开始出加上字符1表示左表,加上2表示右表。
 * 然后在shuffle过程中完成连接,reduce接收到连接的结果,其中每个key的value-list就包含了“grandchild-grandparent”关系。
 * 取出每个key的value-list进行解析,将左表中的child放入一个数组(就一个key),右表中的grandparent放入一个数组,然后对两个数组求笛卡儿积就ko了
 * 
 */
public class selfRelatedMap extends Mapper<LongWritable, Text, Text, Text> {
	@Override
	protected void map(LongWritable key, Text value,
			Mapper<LongWritable, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		String line = value.toString();
		if (line.trim().length() > 0) {
			String str[] = line.split("\t");
			if (str.length == 2) {
				context.write(new Text(str[1]), new Text("1_" + str[0])); // 左表
				context.write(new Text(str[0]), new Text("2_" + str[1])); // 右表
			}
		}

	}
}


 

2.Reduce类

package test.mr.selfrelated;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class selfRelatedRedu extends Reducer<Text, Text, Text, Text> {
	@Override
	protected void reduce(Text key, Iterable<Text> values,
			Reducer<Text, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		List<String> grandsons = new ArrayList<String>();
		List<String> grandparents = new ArrayList<String>();
		for (Text t : values) {
			// 进行value字符串切分
			String str[] = t.toString().split("_");
			if ("1".equals(str[0])) {
				// 左表 //作为孙
				grandsons.add(str[1]);
			} else if ("2".equals(str[0])) {
				// 右表 //作为祖母辈
				grandparents.add(str[1]);
			}
		}
		// 做笛卡尔积
		for (String gc : grandsons) {
			for (String gp : grandparents) {
				context.write(new Text(gc), new Text(gp));
			}
		}
	}
}


 

3.job类

package test.mr.selfrelated;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class selfRelatedMain {
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = new Job(conf);
		job.setJarByClass(selfRelatedMain.class);

		job.setMapperClass(selfRelatedMap.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);

		job.setReducerClass(selfRelatedRedu.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);

		FileInputFormat.addInputPath(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}
}


 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MapReduce 中进行单连接(join)需要使用到 Map 和 Reduce 两个阶段,具体步骤如下: 1. 将两个要连接按照连接字段进行排序和分区,保证相同连接字段值的记录在同一个分区中。 2. 在 Map 阶段,对于每个分区中的记录,将连接字段作为输出的 key,将记录作为输出的 value,然后将它们发送到 Reduce 阶段进行处理。其中,对于第一个的记录,需要在 value 中添加一个标记以区分不同的记录。 3. 在 Reduce 阶段,对于每个连接字段相同的记录,将它们进行组合,生成连接后的记录。具体步骤如下: a. 对于每个连接字段相同的记录,将它们分别存储到两个缓存中,一个缓存存储第一个的记录,另一个缓存存储第二个的记录。 b. 对于每个第一个的记录,将它与第二个的缓存中相同连接字段的记录进行组合,生成连接后的记录。如果第二个的缓存中没有相同连接字段的记录,则不生成连接记录。 4. 将连接后的记录按照连接字段排序,输出最终结果。 需要注意的是,在 MapReduce 中进行单连接操作会产生大量的中间结果,因此需要进行合理的优化和调整,以提高性能和减少资源消耗。例如,可以使用 Combiner 函数来对 Map 阶段的输出进行局部聚合,减少数据传输量和 Reduce 阶段的计算量。同时,也可以对进行预处理和缓存,以减少数据量和加快处理速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值