Hadoop 中的采样器-附主要使用源码

由于最近在研究Hadoop中采样的问题,搞的头很大,今天慢慢有些头绪了。先记录点采样器的问题吧。

Hadoop已经内置的若干个采样器, InputSampler 类实现了Sampler接口,该接口的唯一成员方法是getsampler,返回一系列样本键。这个接口通常不直接由客户端调用,二十由InputSampler类的静态方法writePartitionFile()调用,目的是创建一个顺序文件(SequenceFile)来存储定义分区的键。
简单的代码(权威指南中的):

InputSampler.RandomSampler<IntWritable, NullWritable> sampler = new InputSampler.RandomSampler<IntWritable, NullWritable>(1.0, 20, 3);
Path input = FileInputFormat.getInputPaths(conf)[0];
input = input.makeQualified(input.getFileSystem(conf));
Path partitionFile = new Path(input, "_partitions");
TotalOrderPartitioner.setPartitionFile(conf, partitionFile);
InputSampler.writePartitionFile(conf, sampler);// 目的是创建一个顺序文件来存储定义的分区的键, 这个顺序文件就是路径partitionFile 所指示的文件。

其中 writePartitionFile(JobConf job, InputSampler.Sampler<K,V> sampler)这个函数是将采样的结果排序,然后按照分区的个数n,将排序后的结果平均分为n分,取n-1个分割点,这个分割点具体取的时候,运用了一些4舍5入的方法,最简答的理解就是取后n-1个组中每组的第一个采样值就OK了。


上面提到了SequenceFile. 那这里就简单插一下SequenceFile文件的读问题吧。 目的是用于记录二进制类型的key/value对的,SequenceFile 同样也可作为小文件的容器。提供了Writer,Reader 和 SequenceFile.Sorter 三个类用于完成写,读,和排序。
以下是读一个SequenceFIle 的例子。

SequenceFile.Reader read = null;
 FileSystem fs = FileSystem.get(partitionURI, conf);
read = new SequenceFile.Reader(fs, partitionFile, conf);
IntWritable key = (IntWritable) ReflectionUtils.newInstance(read.getKeyClass(), conf); //顺序文件中的key类型
NullWritable value = (NullWritable) ReflectionUtils.newInstance(read.getValueClass(), conf);//value类型 

while(read.next(key, value)){
// do something you want

       // System.out.println(" The key is "+ key.toString());}

IOUtils.closeStream(read); //最后要关闭read

这里要提醒一下,如果你指定reduce task的个数如果为1,那么即使你采样了,采了很多个,但是writePartitionFile 函数是不会向你指定的顺序文件中写入数据的(想想也是吗?可惜当时脑子坏掉了,就只想着怎么文件是空的,忘记改reduce task的个数了,囧阿)。

这样以来通过读取partitionFile 所指定的SequenceFile 文件中的数据,就可以获得用于分区的 键值。可以我的需求是要记录每个采样值,并且统计每个采样值出现的次数。找了很久的实现方法,关键是我自己又不想自己重新写一个类来继承InputSampler。找了很久,根本搜不到(搜到的全是用采样器来帮助TotalOrderParition的,或者Tera排序的)


函数原型如下:

K[]

getSample(InputFormat<K,V> inf, JobConf job) 
          Randomize the split order, then take the specified number of keys from each split sampled, where each key is selected with the specified probability and possibly replaced by a subsequently selected key when the quota of keys from that split is satisfied.


顾名思义,k[]是用来获得采样的结果序列的。可是实现时又遇到问题。按照我自己设定的输入输出格式,写了如下代码:

IntWrtiable[] k;

InputFormat<IntWritable, NullWritable> inf;

k = sampler.getSample(inf,conf);

之后就是一堆错误,什么key的类型不匹配阿,还有这样定义inf就是错误的,可怜我java不熟悉,有时候很简单的东西我还是弄错,没办法,慢慢进步吧。

后来发现不能定义inf,而是将inf参数写成 conf.getInputFormat() 这样参数部分就没有什么类型不匹配的问题了,又遇到了新的问题,即使我输入是key是IntWritable类型的,可以写成

IntWritable[] k = sampler.getsample(conf.getInputFormat(),conf)又报错,是呢么key是object 不能强制转化成IntWritable。OMG,发现API上将的根本就不详细阿。而且gersample的使用,我搜索都没搜到,我恨不得去StackOverFlow上提问去了。

把老公叫过来调程序,我俩折腾了半天,发现要这样写:

Object[] p = sampler.getSample(conf.getInputFormat(), conf);

这样就OK了,如果要把这些采样结果写进单独的文件中,就使用 FileSystem 和FSDataOutputStream就可以了,要统计结果,定义一个私有静态 hash表就可以了。采样器是我本解段工作的最后一个模块了,下一步就是整合之前的工作了,6月底的时候希望程序和测试实验都结束。

最近很累,又要做项目,又要准备找工作,做个IT女真不容易阿。

谨以此篇文章献给我最爱的老公,么么。(你都不用找工作,跑去香港读博,哼)


有关Hadoop中的采样器,我还遇到了另外一个问题,就是多路径输入的时候,只采特定的一个路径的输入数据,请见我另外一篇博客: 

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

http://blog.csdn.net/kingjinzi_2008/article/details/7695367 这里面有一些可公开的,更加详细的代码。


2012.6.22 夜
DB316
NWPU



























评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值