Hadoop与Spark算法分析(二)——排序算法

数据排序是实际任务执行时非常重要的一步,为后续的数据处理打下基础。

1. 实验准备

本次实验中,每个数据以行的形式保存在输入文件中。其中输入文件通过编写Linux Shell脚本makeNumber.sh随机生成。shell脚本内容如下:

#! /bin/bash
for i in `seq 1 $1`
do
    echo $((RANDOM)) >> $2
done

第1个参数表示输入文件的行数,第2个参数表示输入文件路径。编写完成后,修改脚本权限可执行

$chmod a+x ./makeNumber.sh

运行脚本生成输入文件。例如,随机生成包含10行数字的输入文件,路径为~/testFile

$./makeNumber.sh 10 ~/testFile

2. Hadoop实现

由WordCount过程可知,MapReduce中默认的排序根据key进行,发生在各个reduce过程中。基于这个思想,需要自定义Partition类,以输入数据中可能出现最大值除以系统partition数量的商,作为数据分割的边界增量,保证所有的reduce过程在整体有序。同时,在reduce过程需要将从Map端得到的key作为value输出。具体代码实现如下:

package org.hadoop.test;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.hadoop.test.WordCount.IntSumReducer;
import org.hadoop.test.WordCount.TokenizerMapper;

public class Sort {
    public static class SortMapper
        extends Mapper<Object, Text, IntWritable, IntWritable>{
            private IntWritable data = new IntWritable();
            private IntWritable one = new IntWritable(1);

            public void map(Object key, Text value, Context context) 
                    throws IOException, InterruptedException{
                        String line = value.toString();
                        data.set(Integer.parseInt(line));
                        context.write(data, one);
            }
    }

    public static class SortReducer
        extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable>{
            private IntWritable linenum = new IntWritable(1);

            public void reduce(IntWritable key, Iterable<IntWritable> values, Context context) 
                    throws IOException, InterruptedException{
                        for (IntWritable value : values){
                            context.write(linenum, key);
                            linenum.set(linenum.get()+1);
                        }
            }
    }

    public static class Partition 
        extends Partitioner<IntWritable, IntWritable>{

        @Override
        public int getPartition(IntWritable key, IntWritable value, int numPartitions) {
            // TODO Auto-generated method stub
            int max = 999999;
            int bound = max/numPartitions+1;
            int number = key.get();
            for (int i=0;i<numPartitions;i++){
                if(number < bound*i && number >= bound*(i-1)){
                    return i-1;
                }
            }
            return -1;
        }
    }

    public static void main(String[] args) 
            throws Exception{
                Configuration conf = new Configuration();
                String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
                if (otherArgs.length < 2){
                    System.err.println("Usage: sort <in> <out>");
                    System.exit(2);
                }

                Job job = new Job(conf, "Sort");
                job.setJarByClass(Sort.class);
                job.setMapperClass(SortMapper.class);
                job.setPartitionerClass(Partition.class);
                job.setReducerClass(SortReducer.class);
                job.setOutputKeyClass(IntWritable.class);
                job.setOutputValueClass(IntWritable.class);
                FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
                FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
                System.exit(job.waitForCompletion(true)? 0:1);
    }
}

3. Spark实现

Spark RDD通过sortBy算子执行排序过程,具体实现代码如下:

import org.apache.spark.{SparkConf, SparkContext}

/**
  * Created by rose on 16-4-27.
  */
object Sort {
  def main(args:Array[String]): Unit = {
    if (args.length < 2) {
      println("Usage:<in> <out>")
      return
    }

    val conf = new SparkConf().setAppName("Sort")
    val sc = new SparkContext(conf)
    val textRDD = sc.textFile(args(0))
    val result = textRDD.map(line => line.toInt).sortBy(x => x, true)
    result.saveAsTextFile(args(1))
  }
}

4. 运行过程

1)上传本地文件到HDFS目录下
在HDFS上创建输入文件夹

$hadoop fs -mkdir -p sort/input

上传本地文件到集群的input目录下

$hadoop fs -put ~/file* sort/input

查看集群文件目录

$hadoop fs -ls sort/input

2)运行程序
将排序算法程序Sort打包为后缀名为jar的压缩文件Sort.jar,进入到压缩文件所在文件夹(这里以一个file输入文件和一个output输出文件夹为例说明)。
Hadoop程序运行如下命令执行

$hadoop jar ~/hadoop/Sort.jar org.hadoop.test.Sort sort/input/file sort/hadoop/output

Spark程序运行如下命令执行

$spark-submit --master yanr-client --class Sort ~/spark/Sort.jar hdfs://master:9000/sort/input/file hdfs://master:9000/sort/spark/output

3)查看运行结果
查看Hadoop执行结果

$hadoop fs -ls sort/hadoop/output

查看Spark执行结果

$hadoop fs -ls sort/spark/output

5. 测试对比

这里写图片描述

如图所示为排序测试对比图,两者对于单一文件数据集的排序效率相差不大。Hadoop将数据分区排序,在排序算法的运行时间上更加稳定,而Spark算法采用sortBy算子进行排序计算,有着更大的优化空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值