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

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

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

InputSampler.RandomSampler sampler = new InputSampler.RandomSampler(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 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 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 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



























你可能感兴趣的:(Hadoop学习笔记)