Hadoop实例学习之 CSDN十大常用密码

Hadoop实例:CSDN十大常用密码

一.Hadoop

转自:http://www.datalab.sinaapp.com/?p=92

Hadoop是一个实现了MapReduce计算模型的开源分布式并行编程框架。程序员可以借助Hadoop编写程序,将所编写的程序运行于计算机机群上,从而实现对海量数据的处理。此外,Hadoop还提供一个分布式文件系统(HDFS)及分布式数据库(HBase)用来将数据存储或部署到各个计算节点上。所以,可以大致认为:Hadoop=HDFS+HBase+MapReduce.

Hadoop任务处理的整个流程如下:

二:MapReduce

Hadoop MapReduce将计算任务抽象成map和reduce两个计算过程。一个MapReduce程序首先会把输入数据分割成不相关的若干键/值对(key1/value1)集合,这些键/值对会由多个map任务来并行地处理。MapReduce会对map的输出(一些中间键/值对key2/value2集合)进行Shuffle,按照key2进行排序,并将属于同一个key2的所有value2组合在一起作为reduce任务的输入,由reduce任务计算出最终结果并输出key3/value3。即:

(input)<k1, v1> => map => <k2, v2> => combine => <k2, v2[List]> => reduce => <k3, v3[List]>(output)

三、MapReduce中的Shuffle

Shuffle是指从Map产生输出开始,包括系统执行排序以及传送Map输出到Reducer作为输入的过程。

首先从Map 端开始分析。当Map开始产生输出时,它并不是简单的把数据写到磁盘,因为频繁的磁盘操作会导致性能严重下降。它将数据首先写到内存中的一个缓冲区,并做了一些预排序,以提升效率。这个缓冲区默认大小是100MB。当缓冲区中的数据量达到一个特定阀值(默认是0.80)时,系统将会把缓冲区中的内容spill到磁盘。在spill过程中,Map 的输出将会继续写入到缓冲区,但如果缓冲区已满,Map 就会被阻塞直到spill完成。spill 线程在把缓冲区的数据写到磁盘前,会首先根据数据所属的partition 排序,(partition用于确定每部分数据之后交由哪个reduce继续处理),然后每个partition中的数据再按Key 排序。如果设定了Combiner,将在排序输出的基础上运行Combiner。Combiner 就是一个本地Reducer,使得Map的输出更紧凑,更少的数据会被写入磁盘和传送到Reducer。

每当内存中的数据达到spill 阀值的时候,都会产生一个新的spill 文件,所以在Map任务写完它的最后一个输出记录时,可能会有多个spill文件。在Map任务完成前,所有的spill文件将会被归并为一个已分区和已排序的输出文件。

当spill 文件归并完毕后,Map将删除所有的临时spill 文件,并告知TaskTracker 任务已完成。Map 的输出文件放置在运行Map 任务的TaskTracker 的本地磁盘上,它是运行Reduce 任务的TaskTracker 所需要的输入数据。Reducers 通过HTTP 来拷贝获取对应的输入数据。当所有的Map 输出都被拷贝后,Reduce任务进入排序阶段(更恰当的说应该是归并阶段,因为排序在Map 端就已经完成),这个阶段会对所有的Map 输出进行归并排序。

之后在Reduce 阶段,Reduce 函数会作用在排序输出的每一个key/value对上。这个阶段的输出被直接写到输出文件系统,一般是HDFS。到此,MapReduce 的Shuffle 和Sort 分析完毕。

四、Hadoop实例:CSDN十大密码

(1)输入文件的格式每行为一个账户(用户名#密码#邮箱),例如net123sky # e12345 # song123mail@21cn.com

(2)先通过map/reduce统计每个密码的出现个数,密码为key,再实现对key和value的交换,交换后出现次数为key,通过setSortComparatorClass指定排序函数,让hadoop即会按key降序排序。另外,由于本次试验是在伪分布下进行,只使用了一个Reduce,排序阶段并为指定分区函数。

实际中,利用Hadoop分而治之的计算模型进行全局排序,可以参照快排的思想。快速排序基本步骤就是需要现在所有数据中选取一个作为支点。然后将大于这个支点的放在一边,小于这个支点的放在另一边。然后对两边排序。

设想如果我们有N个支点(这里可以称为标尺),就可以把所有的数据分成N+1个part,将这N+1个part丢给N+1个reduce,每个part由Hadoop自动排序,最后输出N+1个内部有序的文件,再把这N+1个文件首尾相连合并成一个文件,形成全局有序的数据。

由此我们可以归纳出这样一个用hadoop对大量数据排序的步骤:

  1.  对待排序数据进行抽样;
  2.  对抽样数据进行排序,产生标尺;
  3.  Map对输入的每条数据计算其处于哪两个标尺之间;将数据发给对应区间ID的reduce
  4.  Reduce将获得数据直接输出。

这里只是实现了伪分布下单Reduce的全局排序,两轮MapReduce的代码见GitHub,运行结果如下:

其他参考资料:
百度搜索研发部官方博客《使用hadoop进行大规模数据的全局排序》

代码地址:https://github.com/intergret/snippet/blob/master/csdn.java

准备数据代码也来跑一遍吧:

package com.myhadoop.csdn600;
import java.io.IOException;
import java.util.Random;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;




public class Csdn{


public static class CountMapper extends Mapper<Object, Text, Text, IntWritable>{
    
   private final static IntWritable one = new IntWritable(1);
   private Text password = new Text();


   public void map(Object key, Text value, Context context) throws IOException, InterruptedException {


       String eachline=value.toString();
       String [] eachterm=eachline.split("#");


       password.set(eachterm[1]);


    context.write(password, one);  
   }
 
  
public static class CountReducer extends Reducer<Text,IntWritable,Text,IntWritable> {


private IntWritable total = new IntWritable();


public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {


  int sum = 0;
  for (IntWritable val : values) {
    sum += val.get();
  }
  total.set(sum);
  context.write(key,total);
}
}
  


public static class SortMapper extends Mapper<Object, Text, IntWritable,Text>{


   public void map(Object key, Text value, Context context) throws IOException, InterruptedException {


    IntWritable times = new IntWritable(1);
   Text password = new Text();




    String eachline=value.toString();
    String[] eachterm =eachline.split(" ");


    if(eachterm.length==2){
    password.set(eachterm[0]);
    times.set(Integer.parseInt(eachterm[1]));
    context.write(times,password);
    }else{
    password.set("errorpassword");
    context.write(times,password);
    }
   }



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


public void reduce(IntWritable key,Iterable<Text> values, Context context) throws IOException, InterruptedException {


//不同的密码可能出现相同的次数
for (Text val : values) {
password.set(val);
context.write(key,password);
}
}
}
  
  
private static class IntDecreasingComparator extends IntWritable.Comparator {
public int compare(WritableComparable a, WritableComparable b) {
return -super.compare(a, b);
}


public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
return -super.compare(b1, s1, l1, b2, s2, l2);
}
}
  
  


public static void main(String[] args) throws Exception {


   Configuration conf = new Configuration();


   Job job = new Job(conf, "csdn");
   job.setJarByClass(Csdn.class);
   job.setMapperClass(CountMapper.class);
   job.setCombinerClass(CountReducer.class);
   job.setReducerClass(CountReducer.class);


   job.setOutputKeyClass(Text.class);
   job.setOutputValueClass(IntWritable.class);


   //定义一个临时目录,先将词频统计任务的输出结果写到临时目录中, 下一个排序任务以临时目录为输入目录。
FileInputFormat.addInputPath(job, new Path("input/www.csdn.net.sql"));
   Path tempDir = new Path("csdn-temp-" + Integer.toString(new Random().nextInt(Integer.MAX_VALUE))); 
   FileOutputFormat.setOutputPath(job, tempDir);




   if(job.waitForCompletion(true))
{
Job sortJob = new Job(conf, "csdnsort");
sortJob.setJarByClass(Csdn.class);


FileInputFormat.addInputPath(sortJob, tempDir);


sortJob.setMapperClass(SortMapper.class);
FileOutputFormat.setOutputPath(sortJob, new Path("output/csdnout"));


sortJob.setOutputKeyClass(IntWritable.class);
sortJob.setOutputValueClass(Text.class);


sortJob.setSortComparatorClass(IntDecreasingComparator.class);


FileSystem.get(conf).deleteOnExit(tempDir);


System.exit(sortJob.waitForCompletion(true) ? 0 : 1);
}


   System.exit(job.waitForCompletion(true) ? 0 : 1);  
}
}

贴个图:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值