Hadoop 实验:二次排序

一.实验原理

MR默认会对键进行排序,然后有的时候我们也有对值进行排序的需要,如果有内存溢出的问题,就用二次排序来进行对值的排序MR计算过程中,而不是单独来做。
二次排序就是首先按照第一次字段排序,然后对第一字段相同的行按照第二字段排序,注意不能破坏第一次排序结果。

二.实验需要

本实验所需外部 jar 文件都可以在实验集群的/home/hadoop/lib.zip 文件中找到,请自行下载。

1.编写代码

这次我们需要创建两个类
一个是用于来数据的存储
一个是以实现第一字段和第二字段的比较。
IntPair类:

package mr; 
import java.io.DataInput; 
import java.io.DataOutput; 
import java.io.IOException; 
import org.apache.hadoop.io.IntWritable; 
import org.apache.hadoop.io.WritableComparable; 
public class IntPair implements WritableComparable<IntPair> { 
private IntWritable first; 
private IntWritable second; 
public void set(IntWritable first, IntWritable second) { 
this.first = first; 
this.second = second;     
    }
   //注意:需要添加无参的构造方法,否则反射时会报错。 
public IntPair() { 
set(new IntWritable(), new IntWritable()); 
    }
public IntPair(int first, int second) { 
set(new IntWritable(first), new IntWritable(second)); 
    }
    public IntPair(IntWritable first, IntWritable second) { 
            set(first, second); 
    }
    public IntWritable getFirst() {     
    return first; 
    }
    public void setFirst(IntWritable first) { 
            this.first = first; 
    }
    public IntWritable getSecond() { 
    return second; 
    }
    public void setSecond(IntWritable second) { 
    this.second = 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 hashCode() { 
    return first.hashCode() * 163 + second.hashCode(); 
    }
    public boolean equals(Object o) { 
    if (o instanceof IntPair) { 
        IntPair tp = (IntPair) o; 
    return first.equals(tp.first) && second.equals(tp.second); 
    }
    return false; 
    }
    public String toString() { 
    return first + "\t" + second; 
    }
    public int compareTo(IntPair tp) { 
    int cmp = first.compareTo(tp.first); 
    if (cmp != 0) { 
    return cmp; 
    }
    return second.compareTo(tp.second); 
    } 
    }

SecondarySort类
完整代码:

package mr; 
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.NullWritable; 
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; 
public class SecondarySort { 
static class TheMapper extends Mapper<LongWritable, Text, IntPair, NullWritable> 
{ 
    @Override 
protected void map(LongWritable key, Text value, Context context) 
throws IOException, InterruptedException { 
String[] fields = value.toString().split("\t"); 
int field1 = Integer.parseInt(fields[0]); 
int field2 = Integer.parseInt(fields[1]); 
context.write(new IntPair(field1,field2), NullWritable.get()); 
} 
    }
static class TheReducer extends Reducer<IntPair, NullWritable,IntPair, 
    NullWritable> {
    //private static finalTextSEPARATOR=newText("------------------------------------------------"); 
        @Override 
    protected void reduce(IntPair key, Iterable<NullWritable> values, Context 
    context) 
    throws IOException, InterruptedException { 
    context.write(key, NullWritable.get()); 
        } 
    }
    public static class FirstPartitioner extends Partitioner<IntPair, NullWritable> { 
    public int getPartition(IntPair key, NullWritable value, 
    int numPartitions) { 
    return Math.abs(key.getFirst().get()) % numPartitions; 
    } 
    }
    //如果不添加这个类,默认第一列和第二列都是升序排序的。 
    //这个类的作用是使第一列升序排序,第二列降序排序 
    public static class KeyComparator extends WritableComparator { 
    //无参构造器必须加上,否则报错。 
    protected KeyComparator() { 
    super(IntPair.class, true); 
        }
    public int compare(WritableComparable a, WritableComparable b) { 
    IntPair ip1 = (IntPair) a;IntPair ip2 = (IntPair) b; 
    //第一列按升序排序 
    int cmp = ip1.getFirst().compareTo(ip2.getFirst()); 
    if (cmp != 0) { 
    return cmp; 
        }
    //在第一列相等的情况下,第二列按倒序排序 
    return -ip1.getSecond().compareTo(ip2.getSecond()); 
        } 
    }
    //入口程序 
    public static void main(String[] args) throws Exception { 
    Configuration conf = new Configuration(); 
    Job job = Job.getInstance(conf); 
    job.setJarByClass(SecondarySort.class); 
    //设置 Mapper 的相关属性 
    job.setMapperClass(TheMapper.class); 
    //当 Mapper 中的输出的 key 和 value 的类型和 Reduce 输出 
    //的 key 和 value 的类型相同时,以下两句可以省略。 
    //job.setMapOutputKeyClass(IntPair.class); 
    //job.setMapOutputValueClass(NullWritable.class); 
    FileInputFormat.setInputPaths(job, new Path(args[0])); 
    //设置分区的相关属性 
    job.setPartitionerClass(FirstPartitioner.class); 
    //在 map 中对 key 进行排序 
    job.setSortComparatorClass(KeyComparator.class); 
//job.setGroupingComparatorClass(GroupComparator.class); 
//设置 Reducer 的相关属性 
job.setReducerClass(TheReducer.class); 
job.setOutputKeyClass(IntPair.class); 
job.setOutputValueClass(NullWritable.class); 
FileOutputFormat.setOutputPath(job, new Path(args[1])); 
//设置 Reducer 数量 
int reduceNum = 1; 
if(args.length >= 3 && args[2] != null){ 
reduceNum = Integer.parseInt(args[2]); 
}
job.setNumReduceTasks(reduceNum); 
job.waitForCompletion(true); 
} 
}

导入到idea我遇到了2个错误问题:
1.SLF4J-jar包多绑定冲突

从提示信息来看,是hadoop的slf4j 与hbase的slf4j jar包发生了冲突,移除其中一个即可需要删除一个重复类型的jar包。

***2.数组越界:***在这里插入图片描述

Java 83行 FileInputFormat.setInputPaths(job, new Path(args[0]));
在这里插入图片描述
因为我们整个java类没有一个数组的数据只有一个框架结构,需要添加数据进入java类中,但是我们用xftp导入一个数组的.txt的文件,所以这里报错的问题,就调用hadoop jar包方法来解决。

打包提交 打包并上传到Ubantu hadoop 中

使用idea 开发工具将代码打包,选择主类为mr.Counters. 假定打包后的文件为Counters.jar。将打包好的用Xftp导入**/usr/local/hadoop/share/hadoop/里并应用。
在windnows 系统 创建 一个
secsortdata.txt** 内容:
7 444
3 9999
7 333
8
4 22
3 7777
7 555
3 6666
6 0
3 8888
4 11

将secsortdata.txt 文件用Xftp上传至/home/主目录下,这样好查询。

登录hadoop系统

sbin/start-all.sh 启动hadoop 

Jps 查询进程 5个进程就是启动成功!

输入数据查询结果

创建文件夹 :

Hadooop fs -mkdir -p /user/mapreduce/secsort/in/

查询是否创建成功:

扫描二维码关注公众号,回复: 10078769 查看本文章
Hadoop fs -ls /user/mapreduce/secsort/in/

将secsortdata.txt传入hdfs系统中

Hadoop fs -put /home/hadoop/secsortdata.txt /user/mapreduce/secsort/in/

查询是否上传成功:

Hadoop fs -ls /user/mapreduce/secsort/in/

运用jar执行secsortdata.txt 执行结果。

 Hadoop jar SecondarySotr.jar /user/mapreduce/secsort/in/secsortdata.txt  /user/mapreduce/secsort/out

我在运行途中遇到了2个错误:
警告mapred。LocalJobRunner: job_local635467211_0001. lang。例外:. lang。NumberFormatException:用于输入字符串:“7 444”
这里警告不能用\t这些html5标签或者用“\t”;但是还是会继续运行下去。

在这里插入图片描述

****第二个问题:把txt导入到文件里的时候,会提示hdfs:数据源异常问题。
最终在官网上找到答案:这是native库不兼容造成的(本人尝试过替换native库),目前算是Hadoop的一个bug,还没有解决方案,可以忽略掉。
在这里插入图片描述
但是hadoop fs -ls/user/mapreduce/secsort/in/secsortdata.txt 能查询到txt文本已经上传成功。

查询结果:hadoop fs -cat /user/mapreduce/secsort/out/p*****
在这里插入图片描述
二次排序就成功了,在学习中遇到了一些问题,也在逐渐解决问题。加油!

发布了16 篇原创文章 · 获赞 0 · 访问量 636

猜你喜欢

转载自blog.csdn.net/qq_43388040/article/details/103264443
今日推荐