hadoop简单实现文本数据全局排序

来源:互联网 发布:java实训学校 编辑:程序博客网 时间:2024/05/29 04:39

(1)、关于mapreduce

mapreduce很适合数据之间相关性较低且数据量庞大的情况,map操作将原始数据经过特定操作打散后输出,作为中间结果,hadoop通过shuffle操作对中间结果排序,之后,reduce操作接收中间结果并进行汇总操作,最后将结果输出到文件中,从这里也可以看到在hadoop中,hdfs是mapreduce的基石。可以用下面这幅图描述map和reduce的过程:

image

有人用这么一句话解释mapreduce:

We want to count all the books in the library. You count up shelf #1, I count up shelf #2. That’s map. The more people we get, the faster it goes.
我们要数图书馆中的所有书。你数1号书架,我数2号书架。这就是“Map”。我们人越多,数书就更快。

Now we get together and add our individual counts. That’s reduce.
现在我们到一起,把所有人的统计数加在一起。这就是“Reduce”。

(2)、数据准备

将待排序文本上传到hdfs上并放在input文件夹中,在终端执行:hadoop dfs –mkdir input

假设数据文件data.txt放在本地磁盘的/home/leozhang/testdata中,在终端执行:cd /home/leozhang/testdata;hadoop dfs –put data input/

(3)、排序思路

借鉴快速排序的思路:假设为升序排序,那么每完成一次partition,pivot左边所有元素的值都小于等于pivot,而pivot右边的所有元素的值都大于等于pivot,如果现在有N个pivot,那么数据就被map成了N+1个区间,让reducer个数等于N+1,将不同区间的数据发送到相应区间的reducer;hadoop利用shuffle操作将这N+1份数据自动排序,reduce操作只需要接收中间结果后直接输出到文件即可。

由此归纳出用hadoop对大量数据排序的步骤:

1)、对待排序数据进行抽样;

2)、对抽样数据进行排序,产生pivot(例如得到的pivot为:3,9,11);

3)、Map对输入的每条数据计算其处于哪两个pivot之间,之后将数据发给相应的reduce(例如区间划分为:<3、[3,9)、>=9,分别对应reducer0、reducer1、reducer2);

4)、Reduce将获得数据直接输出。

(4)、简单实现

数据抽样由:RandomSelectMapper和RandomSelectReducer完成,数据划分由ReducerPatition完成,排序输出由SortMapper和SortReducer完成,执行顺序为:RandomSelectMapper –> RandomSelectReducer –> SortMapper –> SortReducer。

这个实现方式总觉得不给力,尤其是数据划分那块儿,不知道大家会怎么做,指导一下我吧,呵呵。代码可以从这里(http://files.cnblogs.com/vivounicorn/Sort.rar)得到。

1)、pivot的选取采用随机的方式:

   package MRTEST.Sort;   import java.io.IOException;   import java.util.Random;   import java.util.StringTokenizer;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Mapper;   public class RandomSelectMapper           extends Mapper<Object, Text, Text, Text>{       private static int currentSize = 0;       private Random random = new Random();       public void map(Object key, Text value, Context context)           throws IOException, InterruptedException{           StringTokenizer itr = new StringTokenizer(value.toString());           while(itr.hasMoreTokens()){               currentSize++;               Random ran = new Random();               if(random.nextInt(currentSize) == ran.nextInt(1)){                     Text v = new Text(itr.nextToken());                       context.write(v, v);               }               else{                   itr.nextToken();               }           }       }   }

pivot的排序由hadoop完成:

   package MRTEST.Sort;   import java.io.IOException;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Reducer;   public class RandomSelectReducer           extends Reducer<Text, Text, Text, Text>{       public void reduce(Text key, Iterable<Text> values, Context context)           throws IOException, InterruptedException{           for (Text data : values) {               context.write(null,data);               break;           }       }   }

2)、SortMapper直接读取数据:

   package MRTEST.Sort;   import java.io.IOException;   import java.util.StringTokenizer;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Mapper;   public class SortMapper           extends Mapper<Object, Text, Text, Text> {       public void map(Object key, Text values,               Context context) throws IOException,InterruptedException {             StringTokenizer itr = new StringTokenizer(values.toString());             while (itr.hasMoreTokens()) {                 Text v = new Text(itr.nextToken());                   context.write(v, v);           }       }   }

向相应的Reducer分发数据:

   package MRTEST.Sort;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Partitioner;   public class ReducerPartition           extends Partitioner<Text, Text>{       public int getPartition(Text key, Text value ,int numPartitions){           return HadoopUtil.getReducerId(value, numPartitions);       }   }

最后由SortReducer输出结果:

   package MRTEST.Sort;   import java.io.IOException;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Reducer;   public class SortReducer           extends Reducer<Text, Text, Text, Text> {       public void reduce(Text key, Iterable<Text> values,               Context context) throws IOException, InterruptedException {           for (Text data : values) {               context.write(key,data);           }       }   }

3)、作业的组织由SortDriver完成:

   package MRTEST.Sort;   import java.io.IOException;   import org.apache.hadoop.conf.Configuration;   import org.apache.hadoop.fs.Path;   import org.apache.hadoop.io.Text;   import org.apache.hadoop.mapreduce.Job;   import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;   import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;   import org.apache.hadoop.util.GenericOptionsParser;   public class SortDriver {       public static void runPivotSelect(Configuration conf,                                         Path input,                                         Path output) throws IOException, ClassNotFoundException, InterruptedException{           Job job = new Job(conf, "get pivot");           job.setJarByClass(SortDriver.class);           job.setMapperClass(RandomSelectMapper.class);           job.setReducerClass(RandomSelectReducer.class);           job.setOutputKeyClass(Text.class);           job.setOutputValueClass(Text.class);           FileInputFormat.addInputPath(job, input);           FileOutputFormat.setOutputPath(job, output);           if(!job.waitForCompletion(true)){               System.exit(2);           }       }       public static void runSort(Configuration conf,                                  Path input,                                  Path partition,                                  Path output) throws IOException, ClassNotFoundException, InterruptedException{           Job job = new Job(conf, "sort");           job.setJarByClass(SortDriver.class);           job.setMapperClass(SortMapper.class);           job.setCombinerClass(SortReducer.class);           job.setPartitionerClass(ReducerPartition.class);           job.setReducerClass(SortReducer.class);           job.setOutputKeyClass(Text.class);           job.setOutputValueClass(Text.class);           HadoopUtil.readPartition(conf, new Path(partition.toString() + "\\part-r-00000"));           job.setNumReduceTasks(HadoopUtil.pivots.size());           FileInputFormat.addInputPath(job, input);           FileOutputFormat.setOutputPath(job, output);           System.exit(job.waitForCompletion(true) ? 0 : 1);       }       public static void main(String[] args) throws Exception {           Configuration conf = new Configuration();           String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();           if (otherArgs.length != 3) {             System.err.println("Usage: sort <input> <partition> <output>");             System.exit(2);           }           Path input = new Path(otherArgs[0]);           Path partition = new Path(otherArgs[1]);           Path output = new Path(otherArgs[2]);           HadoopUtil.delete(conf, partition);           HadoopUtil.delete(conf, output);           SortDriver.runPivotSelect(conf,input,partition);           SortDriver.runSort(conf,input, partition, output);       }   }

(5)、打包并测试

在master机器上,单击eclipse的File菜单中的Export,选择Java –> JAR file,单击Next,在左边树形结构中把你想打包的文件勾选,单击Next,再单击Next,在Main class里选择应用程序入口(可选项),最后点Finish,可以看到一个jar文件,例如:Sort.jar。

进入Sort.jar所在路径,在终端输入:hadoop jar Sort.jar input partition output

(5)、查看结果

在http://localhost:50030中可以跟踪所有作业的执行情况。

在hdfs上查看结果,终端输入:hadoop dfs –cat output/*,或者将hdfs上的文件抓到本地查看:hadoop dfs –get output output


0 0
原创粉丝点击