一、 实验目的 1. 进一步立即 MapReduce 思想 2. 编写 SecondarySort 程序。
二、 实验要求 1. 要能理解 MapReduce 编程思想 2. 会编写 MapReduce 版本二次排序程序 3. 其执行并分析执行过程。
三、 实验原理 MR 默认会对键进行排序,然而有的时候我们也有对值进行排序的需求。满足这种 需求一是可以在 reduce 阶段排序收集过来的 values,但是,如果有数量巨大的 values 可 能就会导致内存溢出等问题,这就是二次排序应用的场景——将对值的排序也安排到 MR 计算过程之中,而不是单独来做。 二次排序就是首先按照第一字段排序,然后再对第一字段相同的行按照第二字段排 序,注意不能破坏第一次排序的结果。
四、 实验步骤
新建一个IntPair类
package com.buaa;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
public class IntPair implements WritableComparable<IntPair>{
private int first;
private int second;
public IntPair(){
}
public IntPair(int left, int right){
set(left, right);
}
public void set(int left, int right){
first = left;
second = right;
}
@Override
public void readFields(DataInput in) throws IOException{
first = in.readInt();
second = in.readInt();
}
@Override
public void write(DataOutput out) throws IOException{
out.writeInt(first);
out.writeInt(second);
}
@Override
public int compareTo(IntPair o)
{
if (first != o.first){
return first < o.first ? -1 : 1;
}else if (second != o.second){
return second < o.second ? -1 : 1;
}else{
return 0;
}
}
@Override
public int hashCode(){
return first * 157 + second;
}
@Override
public boolean equals(Object right){
if (right == null)
return false;
if (this == right)
return true;
if (right instanceof IntPair){
IntPair r = (IntPair) right;
return r.first == first && r.second == second;
}else{
return false;
}
}
public int getFirst(){
return first;
}
public int getSecond(){
return second;
}
}
新建一个SecondarySort类
package com.buaa;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
@SuppressWarnings("deprecation")
public class SecondarySort {
public static class Map extends Mapper<LongWritable, Text, IntPair, IntWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
int left = 0;
int right = 0;
if (tokenizer.hasMoreTokens()) {
left = Integer.parseInt(tokenizer.nextToken());
if (tokenizer.hasMoreTokens())
right = Integer.parseInt(tokenizer.nextToken());
context.write(new IntPair(left, right), new IntWritable(right));
}
}
}
/*
* 自定义分区函数类FirstPartitioner,根据 IntPair中的first实现分区
*/
public static class FirstPartitioner extends Partitioner<IntPair, IntWritable>{
@Override
public int getPartition(IntPair key, IntWritable value,int numPartitions){
return Math.abs(key.getFirst() * 127) % numPartitions;
}
}
/*
* 自定义GroupingComparator类,实现分区内的数据分组
*/
@SuppressWarnings("rawtypes")
public static class GroupingComparator extends WritableComparator{
protected GroupingComparator(){
super(IntPair.class, true);
}
@Override
public int compare(WritableComparable w1, WritableComparable w2){
IntPair ip1 = (IntPair) w1;
IntPair ip2 = (IntPair) w2;
int l = ip1.getFirst();
int r = ip2.getFirst();
return l == r ? 0 : (l < r ? -1 : 1);
}
}
public static class Reduce extends Reducer<IntPair, IntWritable, Text, IntWritable> {
public void reduce(IntPair key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
for (IntWritable val : values) {
context.write(new Text(Integer.toString(key.getFirst())), val);
}
}
}
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
// 读取配置文件
Configuration conf = new Configuration();
// 判断路径是否存在,如果存在,则删除
Path mypath = new Path(args[1]);
FileSystem hdfs = mypath.getFileSystem(conf);
if (hdfs.isDirectory(mypath)) {
hdfs.delete(mypath, true);
}
Job job = new Job(conf, "secondarysort");
// 设置主类
job.setJarByClass(SecondarySort.class);
// 输入路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
// 输出路径
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// Mapper
job.setMapperClass(Map.class);
// Reducer
job.setReducerClass(Reduce.class);
// 分区函数
job.setPartitionerClass(FirstPartitioner.class);
// 本示例并没有自定义SortComparator,而是使用IntPair中compareTo方法进行排序 job.setSortComparatorClass();
// 分组函数
job.setGroupingComparatorClass(GroupingComparator.class);
// map输出key类型
job.setMapOutputKeyClass(IntPair.class);
// map输出value类型
job.setMapOutputValueClass(IntWritable.class);
// reduce输出key类型
job.setOutputKeyClass(Text.class);
// reduce输出value类型
job.setOutputValueClass(IntWritable.class);
// 输入格式
job.setInputFormatClass(TextInputFormat.class);
// 输出格式
job.setOutputFormatClass(TextOutputFormat.class);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
导入lib包
步骤如下:
#导入hadoop文件夹路径下的lib包。
1.点击file>Project Structure>Modules>+号>Library下的java找到你自己的lib文件然后ok。完成后打jar包。
jar包操作如下:
勾选Include in project build 点击ok就完成了jar的打包
然后点击Build
完成后就会出现一下jar包
然后将这个包用ftp上传到hadoop中
然后用
用start-all.sh启动hadoop
创建输入和输出的文件夹;
2.创建hadoop fs -mkdir -p /datas/in , hadoop fs -mkdir -p /datas/out
3创建secsortdata.txt文档
用ftp传到hadoop中。
5把上传到hadoop中的txt文档用hadoop fs -put secsortdata.txt /datas/in上传到hdfs中
6.在你java的jar包路径下执行
hadoop jar wordcount.jar /datas/in/secsortdata.txt /datas/out
然后用hadoop fs -cat /datas/out/part-r-00000
查看
这样就成功了。