直接附代码,说明都在源码里了。

 package com.hadoop.totalsort;

 import java.io.IOException;
 import java.util.ArrayList;

 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.LongWritable;
 import org.apache.hadoop.io.NullWritable;
 import org.apache.hadoop.io.SequenceFile;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.mapred.FileInputFormat;
 import org.apache.hadoop.mapred.FileSplit;
 import org.apache.hadoop.mapred.InputSplit;
 import org.apache.hadoop.mapred.JobConf;
 import org.apache.hadoop.mapred.LineRecordReader;
 import org.apache.hadoop.mapred.RecordReader;
 import org.apache.hadoop.mapred.Reporter;
 import org.apache.hadoop.util.IndexedSortable;
 import org.apache.hadoop.util.QuickSort;

 public class SamplerInputFormat extends FileInputFormat<Text, Text> {  

     static final String PARTITION_FILENAME = "_partition.lst";
     static final String SAMPLE_SIZE = "terasort.partitions.sample";
     private static JobConf lastConf = null;
     private static InputSplit[] lastResult = null;  

     static class TextSampler implements IndexedSortable {  

         public ArrayList<Text> records = new ArrayList<Text>();  

         public int compare(int arg0, int arg1) {
             Text right = records.get(arg0);
             Text left = records.get(arg1);  

             return right.compareTo(left);
         }  

         public void swap(int arg0, int arg1) {
             Text right = records.get(arg0);
             Text left = records.get(arg1);  

             records.set(arg0, left);
             records.set(arg1, right);
         }  

         public void addKey(Text key) {
             records.add(new Text(key));
         }  

         //将采集出来的key数据排序
         public Text[] createPartitions(int numPartitions) {
             int numRecords = records.size();
             if (numPartitions > numRecords) {
                 throw new IllegalArgumentException("Requested more partitions than input keys (" + numPartitions +
                         " > " + numRecords + ")");
             }
             new QuickSort().sort(this, 0, records.size());
             float stepSize = numRecords / (float) numPartitions;  //采集的时候应该是采了100条记录,从10个分片查找的,此处再取numPartitions-1条
             Text[] result = new Text[numPartitions - 1];
             for (int i = 1; i < numPartitions; ++i) {
                 result[i - 1] = records.get(Math.round(stepSize * i));
             }
             return result;
         }  

     }  

     public static void writePartitionFile(JobConf conf, Path partFile) throws IOException {
         //前段代码从分片中采集数据,通过sampler.addKey存入TextSampler中的records数组
         SamplerInputFormat inputFormat = new SamplerInputFormat();
         TextSampler sampler = new TextSampler();
         Text key = new Text();
         Text value = new Text();  

         int partitions = conf.getNumReduceTasks(); // Reducer任务的个数
         long sampleSize = conf.getLong(SAMPLE_SIZE, 100); // 采集数据-键值对的个数
         InputSplit[] splits = inputFormat.getSplits(conf, conf.getNumMapTasks());// 获得数据分片
         int samples = Math.min(10, splits.length);// 采集分片的个数   ,采集10个分片
         long recordsPerSample = sampleSize / samples;// 每个分片采集的键值对个数
         int sampleStep = splits.length / samples; // 采集分片的步长   ,总的分片个数/要采集的分片个数
         long records = 0;  

         for (int i = 0; i < samples; i++) {  //1...10分片数
             RecordReader<Text, Text> reader = inputFormat.getRecordReader(splits[sampleStep * i], conf, null);
             while (reader.next(key, value)) {
                 sampler.addKey(key);   //将key值增加到sampler的records数组
                 records += 1;
                 if ((i + 1) * recordsPerSample <= records) {  //目的是均匀采集各分片的条数,比如采集到第5个分片,那么记录条数应该小于5个分片应该的条数
                     break;
                 }
             }
         }
         FileSystem outFs = partFile.getFileSystem(conf);
         if (outFs.exists(partFile)) {
             outFs.delete(partFile, false);
         }
         SequenceFile.Writer writer = SequenceFile.createWriter(outFs, conf, partFile, Text.class, NullWritable.class);
         NullWritable nullValue = NullWritable.get();
         for (Text split : sampler.createPartitions(partitions)) {  //调用createPartitions方法,排序采集出来的数据,并取partitions条
             writer.append(split, nullValue);
         }
         writer.close();  

     }  

     static class TeraRecordReader implements RecordReader<Text, Text> {  

         private LineRecordReader in;
         private LongWritable junk = new LongWritable();
         private Text line = new Text();
         private static int KEY_LENGTH = 10;  

         public TeraRecordReader(Configuration job, FileSplit split) throws IOException {
             in = new LineRecordReader(job, split);
         }  

         public void close() throws IOException {
             in.close();
         }  

         public Text createKey() {
             // TODO Auto-generated method stub
             return new Text();
         }  

         public Text createValue() {
             return new Text();
         }  

         public long getPos() throws IOException {
             // TODO Auto-generated method stub
             return in.getPos();
         }  

         public float getProgress() throws IOException {
             // TODO Auto-generated method stub
             return in.getProgress();
         }  

         public boolean next(Text arg0, Text arg1) throws IOException {
             if (in.next(junk, line)) {   //调用父类方法,将value值赋给key
                // if (line.getLength() < KEY_LENGTH) {
                     arg0.set(line);
                     arg1.clear();
 //                } else {
 //                    byte[] bytes = line.getBytes(); // 默认知道读取要比较值的前10个字节 作为key
 //                                                    // 后面的字节作为value;
 //                    arg0.set(bytes, 0, KEY_LENGTH);
 //                    arg1.set(bytes, KEY_LENGTH, line.getLength() - KEY_LENGTH);
 //                }
                 return true;
             } else {
                 return false;
             }
         }  

     }  

     @Override
     public InputSplit[] getSplits(JobConf conf, int splits) throws IOException {
         if (conf == lastConf) {
             return lastResult;
         }
         lastConf = conf;
         lastResult = super.getSplits(lastConf, splits);
         return lastResult;  

     }  

     public org.apache.hadoop.mapred.RecordReader<Text, Text> getRecordReader(InputSplit arg0, JobConf arg1,
             Reporter arg2) throws IOException {
         return new TeraRecordReader(arg1, (FileSplit) arg0);
     }  

 }  

转载自:http://www.open-open.com/lib/view/open1381329062408.html

mapreduce实现全局排序的更多相关文章

  1. MapReduce TotalOrderPartitioner 全局排序

    我们知道Mapreduce框架在feed数据给reducer之前会对map output key排序,这种排序机制保证了每一个reducer局部有序,hadoop 默认的partitioner是Has ...

  2. 三种方法实现Hadoop(MapReduce)全局排序(1)

    我们可能会有些需求要求MapReduce的输出全局有序,这里说的有序是指Key全局有序.但是我们知道,MapReduce默认只是保证同一个分区内的Key是有序的,但是不保证全局有序.基于此,本文提供三 ...

  3. Mapreduce的排序(全局排序、分区加排序、Combiner优化)

    一.MR排序的分类 1.部分排序:MR会根据自己输出记录的KV对数据进行排序,保证输出到每一个文件内存都是经过排序的: 2.全局排序: 3.辅助排序:再第一次排序后经过分区再排序一次: 4.二次排序: ...

  4. 大数据mapreduce全局排序top-N之python实现

    a.txt.b.txt文件如下: a.txt hadoop hadoop hadoop hadoop hadoop hadoop hadoop hadoop hadoop hadoop hadoop ...

  5. MapReduce怎么优雅地实现全局排序

    思考 想到全局排序,是否第一想到的是,从map端收集数据,shuffle到reduce来,设置一个reduce,再对reduce中的数据排序,显然这样和单机器并没有什么区别,要知道mapreduce框 ...

  6. Hadoop对文本文件的快速全局排序

    一.背景 Hadoop中实现了用于全局排序的InputSampler类和TotalOrderPartitioner类,调用示例是org.apache.hadoop.examples.Sort. 但是当 ...

  7. 一起学Hadoop——TotalOrderPartitioner类实现全局排序

    Hadoop排序,从大的范围来说有两种排序,一种是按照key排序,一种是按照value排序.如果按照value排序,只需在map函数中将key和value对调,然后在reduce函数中在对调回去.从小 ...

  8. MapReduce分区和排序

    一.排序 排序: 需求:根据用户每月使用的流量按照使用的流量多少排序 接口-->WritableCompareable 排序操作在hadoop中属于默认的行为.默认按照字典殊勋排序. 排序的分类 ...

  9. Hadoop学习笔记—11.MapReduce中的排序和分组

    一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出,在Step1.4也就是第四步中,需要对不同分区中的数据进行排 ...

随机推荐

  1. 九度OJ 1501 最大连续子序列乘积 -- 动态规划

    题目地址:http://ac.jobdu.com/problem.php?pid=1501 题目描述: 给定一个浮点数序列(可能有正数.0和负数),求出一个最大的连续子序列乘积. 输入: 输入可能包含 ...

  2. a标签根据js返回值判断页面是否跳转

    a标签再跳转之前先判断是否符合条件,符合可以跳转,不符合不可以跳转. 自己遇到的问题是:在js方法中根据条件就return结果,但是不行. 原因是:在js方法中return后不会结束整个js方法(ac ...

  3. WIN7中oracle10g的安装注意事项

    1.本次安装数据库版本为10.2.0.1,操作系统版本为windows7 32位 2.注意在"setup.exe"中以右键属性后,设置以兼容模式及以管理员身份运行该程序:在%安装文 ...

  4. Javascript中的迭代、归并方法

    迭代方法 在Javascript中迭代方法个人觉得尤为重要,在很多时候都会有实际上的需求,javascript提供了5个迭代方法来供我们操作,它们分别为: every() 对数组中的每一个项运用给定的 ...

  5. winFrom窗体样式

    ControlBox窗口样式:确定窗体是否有"控件/系统"菜单框. 设置为隐藏 False AutoSizeMode  GrowAndShrink 指定用户界面元素自动调整自身大小 ...

  6. centos用yum安装mysql-server

    1.安装:#yum -y install mysql-server 2.修改配置:#vi /etc/my.cnf 暂时修改一下编码(添加在密码下方添加): default-character-set ...

  7. php查询ip地址来源归属地的脚本

    <?php header('Content-Type:text/html;charset=utf-8'); if($_GET['sub']){ $ip = $_GET['ip']; $msg = ...

  8. PHP学习心得(八)——运算符

    运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西.所以可以认为函数或任何会返回一个值(例如 print)的结构是运算符,而那些没有返回值的( ...

  9. log4j记录运行日志

    1.在工程中导入log4j-1.2.15.jar的jar包2.新建测试类 package control; import org.apache.log4j.Logger; import org.apa ...

  10. hdu5548

    2015ACM/ICPC亚洲区上海站LCM WALK 题意:定义了一种走法,就是从当前的点为sx,sy,可以走到ex,ey;并且ex = sx + z,或者 ey = sy + z, 其中z为lcm( ...