Hadoop :Join 操作

Hadoop :Join 操作

一、 实验目的

  1. 基于 MapReduce 思想,编写两文件 Join 操作的程序。

二、 实验要求
2. 能够理解 MapReduce 编程思想,然后会编写 MapReduce 版本 Join 程序,并能执
行该程序和分析执行过程。
三、 实验背景
3. 概述
对于 RDBMS 中的 Join 操作大伙一定非常熟悉,写 SQL 的时候要十分注意细节,稍
有差池就会耗时巨久造成很大的性能瓶颈,而在 Hadoop 中使用 MapReduce 框架进行 Join
的操作时同样耗时,但是由于 Hadoop 的分布式设计理念的特殊性,因此对于这种 Join
操作同样也具备了一定的特殊性。
4. 原理
使用 MapReduce 实现 Join 操作有多种实现方式:
在 Reduce 端连接为最为常见的模式:
Map 端的主要工作:为来自不同表(文件)的 key/value 对打标签以区别不同来源的记
录。然后用连接字段作为 key,其余部分和新加的标志作为 value,最后进行输出。
Reduce 端的主要工作:在 Reduce 端以连接字段作为 key 的分组已经完成,我们只
需要在每一个分组当中将那些来源于不同文件的记录(在 map 阶段已经打标志)分开,最
后进行笛卡尔只就 OK 了。
在 Map 端进行连接使用场景:一张表十分小、一张表很大。
用法:在提交作业的时候先将小表文件放到该作业的 DistributedCache 中,然后从
DistributeCache 中取出该小表进行 Join key / value 解释分割放到内存中(可以放大 Hash
Map 等等容器中)。然后扫描大表,看大表中的每条记录的 Join key /value 值是否能够在
内存中找到相同 Join key 的记录,如果有则直接输出结果。
SemiJoin
SemiJoin 就是所谓的半连接,其实仔细一看就是 Reduce Join 的一个变种,就是在
map 端过滤掉一些数据,在网络中只传输参与连接的数据不参与连接的数据不必在网络
中进行传输,从而减少了 shuffle 的网络传输量,使整体效率得到提高,其他思想和 Reduce
Join 是一模一样的。说得更加接地气一点就是将小表中参与 Join 的 key 单独抽出来通过
DistributedCach 分发到相关节点,然后将其取出放到内存中(可以放到 HashSet 中),在
map 阶段扫描连接表,将 Join key 不在内存 HashSet 中的记录过滤掉,让那些参与 Join
的记录通过 shuffle 传输到 Reduce 端进行 Join 操作,其他的和 Reduce Join 都是一样的。

实现步骤
1.先准备两个txt文件 (我创建的是 data.txt 和 info.txt 文件)
Hadoop :Join 操作_第1张图片
Hadoop :Join 操作_第2张图片
将这两个文档用 Xftp 传入到 虚拟机中
注意我传过去的文件目录哟
Hadoop :Join 操作_第3张图片
2.在IntelliJ IDEA 中编写 Java代码:
创建一个MRJoin类:
MRJoin类代码:
注意:这里需要在IntelliJ IDEA中引用lib.jar包(没有的去Hadoop里面去拉下来)

package mr;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
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.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.util.GenericOptionsParser;
public class MRJoin {
    public static class MR_Join_Mapper extends Mapper {
        @Override
        protected void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
// 获取输入文件的全路径和名称
            String pathName = ((FileSplit) context.getInputSplit()).getPath(). toString();
            if (pathName.contains("data.txt")) {
                String values[] = value.toString().split("\t");
                if (values.length < 3) {
// data 数据格式不规范,字段小于 3,抛弃数据
                    return;
                } else {
// 数据格式规范,区分标识为 1
                    TextPair tp = new TextPair(new Text(values[1]), new Text("1"));
                    context.write(tp, new Text(values[0] + "\t" + values[2]));
                }
            }
            if (pathName.contains("info.txt")) {
                String values[] = value.toString().split("\t");
                if (values.length < 2) {// data 数据格式不规范,字段小于 2,抛弃数据
                    return;
                } else {
// 数据格式规范,区分标识为 0
                    TextPair tp = new TextPair(new
                            Text(values[0]), new Text("0"));
                    context.write(tp, new Text(values[1]));
                }
            }
        }
    }
    public static class MR_Join_Partitioner extends Partitioner {
        @Override
        public int getPartition(TextPair key, Text value, int numParititon) {
            return Math.abs(key.getFirst().hashCode() * 127) % numParititon;
        }
    }
    public static class MR_Join_Comparator extends WritableComparator {
        public MR_Join_Comparator() {
            super(TextPair.class, true);
        }
        public int compare(WritableComparable a, WritableComparable b) {
            TextPair t1 = (TextPair) a;
            TextPair t2 = (TextPair) b;
            return t1.getFirst().compareTo(t2.getFirst());
        }
    }
    public static class MR_Join_Reduce extends Reducer {protected void Reduce(TextPair key, Iterable values, Context
            context)
            throws IOException, InterruptedException {
        Text pid = key.getFirst();
        String desc = values.iterator().next().toString();
        while (values.iterator().hasNext()) {
            context.write(pid, new Text(values.iterator()
                    .next().toString() + "\t" + desc));
        }
    }
    }
    public static void main(String agrs[])
            throws IOException, InterruptedException, ClassNotFoundException {
        Configuration conf = new Configuration();
        GenericOptionsParser parser = new GenericOptionsParser(conf, agrs);
        String[] otherArgs = parser.getRemainingArgs();
        if (agrs.length < 3) {
            System.err.println("Usage: MRJoin   ");
            System.exit(2);
        }
        Job job = new Job(conf, "MRJoin");
// 设置运行的 job
        job.setJarByClass(MRJoin.class);
// 设置 Map 相关内容
        job.setMapperClass(MR_Join_Mapper.class);
// 设置 Map 的输出
        job.setMapOutputKeyClass(TextPair.class);
        job.setMapOutputValueClass(Text.class);
// 设置 partition
        job.setPartitionerClass(MR_Join_Partitioner.class);
// 在分区之后按照指定的条件分组
        job.setGroupingComparatorClass(MR_Join_Comparator.class);
// 设置 Reduce
        job.setReducerClass(MR_Join_Reduce.class);
// 设置 Reduce 的输出
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
// 设置输入和输出的目录
        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileInputFormat.addInputPath(job, new Path(otherArgs[1]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[2]));
// 执行,直到结束就退出
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}
class TextPair implements WritableComparable {
    private Text first;
    private Text second;
    public TextPair() {
        set(new Text(), new Text());
    }
    public TextPair(String first, String second) {
        set(new Text(first), new Text(second));
    }
    public TextPair(Text first, Text second) {
        set(first, second);
    }public void set(Text first, Text second) {
        this.first = first;
        this.second = second;
    }
    public Text getFirst() {
        return first;
    }
    public Text getSecond() {
        return second;
    }
    public void write(DataOutput out) throws IOException {
        first.write(out);
        second.write(out);
    }
    public void readFields(DataInput in) throws IOException {
        first.readFields(in);
        second.readFields(in);
    }
    public int compareTo(TextPair tp) {
        int cmp = first.compareTo(tp.first);
        if (cmp != 0) {
            return cmp;
        }
        return second.compareTo(tp.second);
    }
}

将这个Java程序打包用xftp上传到Hadoop中:
注意我的路径:
Hadoop :Join 操作_第4张图片
我这里打的包,叫做demo3.jar

3.进入虚拟机终端执行以下步骤:
(注意我在Hadoop中进入的文件路径)

首先在Hadoop中创建虚拟的文件夹
创建的命令:

hadoop fs -mkdir -p /(这里是自己创建的文件夹名)/

创建好了就可以查看是否创建好
查看命令:

 hadoop fs -ls /(这里是自己创建的文件夹名)/

例如我这里查看:
创建好的
再将虚拟机中的两个文档放在刚刚创建的虚拟文件夹目录下:

命令:

hadoop fs -put 文档名 /(创建的虚拟目录)/

例如:
在这里插入图片描述
在这里插入图片描述
这是放入两个文件的步骤。
再查看是否放进去了
例:
Hadoop :Join 操作_第5张图片
发现有文档,进入你上传的jar的路径下:
例:在这里插入图片描述
再执行:
例:在这里插入图片描述
执行成功的图片如下:Hadoop :Join 操作_第6张图片
这样就成功了。

你可能感兴趣的:(Hadoop,Hadoop:join)