Hadoop-采样器-多输入路径-只采一个文件-(MultipleInputs+getsample(conf.getInputFormat)

之前弄采样器,以为已经结束了工作,结果现在又遇到了问题,因为我的输入有两个文件,设计要求是先只采样其中的大文件(未来是两个文件分别采样的),只有一个输入文件且采样时,使用采样器的代码是:

  1. Path input = new Path(args[0].toString());  
  2. input = input.makeQualified(input.getFileSystem(conf));  
  3.   
  4. InputSampler.IntervalSampler<Text, NullWritable> sampler = new InputSampler.IntervalSampler<Text, NullWritable>(0.45);  
Path input = new Path(args[0].toString());
input = input.makeQualified(input.getFileSystem(conf));

InputSampler.IntervalSampler<Text, NullWritable> sampler = new InputSampler.IntervalSampler<Text, NullWritable>(0.4, 5);
  1. // 这句话的意思是两个分区,  
// 这句话的意思是两个分区,
  1. // K[] getSample(InputFormat<K,V> inf, JobConf job)  函数原型  
  2.   
  3. String skewuri_out = args[2] + "/sample_list"// 存放采样的结果,不是分区的结果  
  4. FileSystem fs = FileSystem.get(URI.create(skewuri_out), conf);  
  5. FSDataOutputStream fs_out = fs.create(new Path(skewuri_out));  
  6.   
  7. final InputFormat inf = conf.getInputFormat();//这个是获得Jobconf的InputFormat  
  8. Object[] p = sampler.getSample(inf, conf);// 输出采样的结果,必须前面是Object类型,换成I那头Writable就不管用了,不知道为什么  
// K[] getSample(InputFormat<K,V> inf, JobConf job)  函数原型

String skewuri_out = args[2] + "/sample_list"; // 存放采样的结果,不是分区的结果
FileSystem fs = FileSystem.get(URI.create(skewuri_out), conf);
FSDataOutputStream fs_out = fs.create(new Path(skewuri_out));

final InputFormat inf = conf.getInputFormat();//这个是获得Jobconf的InputFormat
Object[] p = sampler.getSample(inf, conf);// 输出采样的结果,必须前面是Object类型,换成I那头Writable就不管用了,不知道为什么



但是这样问题就来了,如果我写了两个Mapper类,分别为Map1class,Map2class,现在两个class分别处理两个不同输入路径的数据,目前是指定输入数据的格式是相同的,那么可以用MultipleInputs 来实现:

  1. MultipleInputs.addInputPath(conf, new Path(args[0]), Definemyself.class,Map1class.class);  
  2. MultipleInputs.addInputPath(conf, new Path(args[1]), Definemyself.class,Map2class.class);  
MultipleInputs.addInputPath(conf, new Path(args[0]), Definemyself.class,Map1class.class);
MultipleInputs.addInputPath(conf, new Path(args[1]), Definemyself.class,Map2class.class);

//Definemyself.class 是我自定义的继承了FileInputFormat ,并且实现了WritableComparable接口

//继承FileInputFormat 是采样的需要,实现WritableComparable接口,是因为我在join的时候想整体数据进行序列化,我自己也解释不明白这个序列化,可以理解成C里面的结构体吧,就是作为一个整体,可以toString()输出。

原型是:public class Definemyself extends FileInputFormat<Text,Text> implements WritableComparable{...}

这个问题从昨晚就困扰我,上周做梦采样,这种做梦还是采样。中午和老公出去吃的,因为要好好探讨一下这个问题,我的理论就是既然系统提供MultipleInputs,同时Jobconf有能调用getInputFormat(),就肯定有办法二者同时使用,不让就矛盾了,傻子才会建立这样的系统呢。

终于,吃完饭回来,我又尝试了一下想法,终于让我给解决了,即如何有两个输入路径的情况下,只对一个输入路径中的文件进行采样,啊哈,答案很简单!见下:

首先修改 Definemyself.class,使其在输出的时候能够分辨是哪个表的,这里我使用最简单的方法,两个表的长度不一样,我通过,长的我称为long表,短的我成为short表,主要就是修改这个class里面的next函数。以下是Definemyself.class中的最重要的函数。

  1. class EmployeeRecordReader implements RecordReader<Text, Text> {  
  2.                 private LineRecordReader in;  
  3. private LongWritable junk = new LongWritable();  
  4. private Text line = new Text();  
  5. private int KEY_LENGTH = 10;  
  6. public boolean next(Text key, Text value) throws IOException {  
  7. if (in.next(junk, line)) {  
  8. String[] lines = line.toString().split(",");  
  9. if (lines.length ==9) { // 这个是大表,也就是要采样的表  
  10. // System.out.println("The line in next of Employee is "+ line);  
  11.                                         deptno = lines[7];  
  12. //很多写全排序的,不论是对整数,还是对字符串,都采用的下面这种写法,自己查去,不过对于表的一行有很多列,只取其中的一列作为排序的key时value.set要做更改。就是输出正行,别的博客中都是些的value = new Text(), 太局限了,只适合字符串全局排序时使用。其实下面的if... else 条件可以省略,留下只是提醒自己,如果从表中抽取的key值占的字节太长时,要做一些处理。  
  13. if (deptno.length() < KEY_LENGTH) {  
  14.     key.set(new Text(deptno));  
  15.     value.set(new Text(line+","+"0"));// 题阿  
  16. else {  
  17.     key.set(new Text(deptno));  
  18.     value.set(new Text(line+","+"0"));  
  19. }  
  20. return true;  
  21. }   
  22. else if (lines.length !=9) {// 断表的处理  
  23. System.out.println("(for short.txt)The line in next of Employee is "+ line);  
  24. deptno = lines[0];// 每列较长的文件中,貌似第5列是depto吧,先这么指定吧  
  25. if (deptno.length() < KEY_LENGTH /* &&(!lines[8].equals("0")) */) {  
  26.     key.set(new Text(deptno));  
  27.     value.set(new Text(line+","+"1"));  
  28. else{  
  29.     key.set(new Text(deptno));  
  30.     value.set(new Text(line+","+"1"));// 1为  
  31. }  
  32. return true;  
  33. }  
  34. else return false;  
  35.   
  36. else {  
  37. return false;  
  38. }  
  39. }  
  40. }  
class EmployeeRecordReader implements RecordReader<Text, Text> {
                private LineRecordReader in;
private LongWritable junk = new LongWritable();
private Text line = new Text();
private int KEY_LENGTH = 10;
public boolean next(Text key, Text value) throws IOException {
if (in.next(junk, line)) {
String[] lines = line.toString().split(",");
if (lines.length ==9) { // 这个是大表,也就是要采样的表
// System.out.println("The line in next of Employee is "+ line);
                                        deptno = lines[7];
//很多写全排序的,不论是对整数,还是对字符串,都采用的下面这种写法,自己查去,不过对于表的一行有很多列,只取其中的一列作为排序的key时value.set要做更改。就是输出正行,别的博客中都是些的value = new Text(), 太局限了,只适合字符串全局排序时使用。其实下面的if... else 条件可以省略,留下只是提醒自己,如果从表中抽取的key值占的字节太长时,要做一些处理。
if (deptno.length() < KEY_LENGTH) {
    key.set(new Text(deptno));
    value.set(new Text(line+","+"0"));// 题阿
} else {
    key.set(new Text(deptno));
    value.set(new Text(line+","+"0"));
}
return true;
} 
else if (lines.length !=9) {// 断表的处理
System.out.println("(for short.txt)The line in next of Employee is "+ line);
deptno = lines[0];// 每列较长的文件中,貌似第5列是depto吧,先这么指定吧
if (deptno.length() < KEY_LENGTH /* &&(!lines[8].equals("0")) */) {
    key.set(new Text(deptno));
    value.set(new Text(line+","+"1"));
} else{
    key.set(new Text(deptno));
    value.set(new Text(line+","+"1"));// 1为
}
return true;
}
else return false;

} else {
return false;
}
}
}


以上的更改就是两个表进来,都可通过此类进行输入,无须针对两个表,要写两个继承FileInputFormat并实现WritableComparable接口的类。下面才是如何让才采样器只采一个文件的,啊哈!答案说出来笑死人了,那就是利用MultipleInputs先指定要采样的那个输入路径,然后调用采样器,采样结束后于采样相关的流、文件什么的进行关闭,最后再用MultipleInputs指定第二个输入路径。这样路径一的文件(可以包含多个文本,你懂的)先采样,然后路径一和路径二的文件都进入map了,map再根据一些额外的信息判断来自那个路径的数据。

        MultipleInputs.addInputPath(conf, new Path(args[0]), Definemyself.class,Mapclass.class);//第一个输入路径

        /*********下面采样**********更多采样的细节见我领一篇博客,不一样的视角那篇***********/

        Path input = new Path(args[0].toString());
        input = input.makeQualified(input.getFileSystem(conf));

        InputSampler.RandomSampler<Text, NullWritable> sampler = new InputSampler.RandomSampler<Text, NullWritable>(0.4,20, 5);

        /...........此处省略细节................/

        IOUtils.closeStream(fs_out);// 关闭流,有关采样的结束了。

         /...............此处添加一些其他的需要的工作,例如分布式缓存啦,Hashtable的处理阿............../

         MultipleInputs.addInputPath(conf, new Path(args[3]), Definemyself.class, Mapclass.class); //最后指定输入的第二条路径
 
         JobClient.runJob(conf);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值