由於最近在研究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的個數了,囧阿)。