• hadoop 第一个 mapreduce 程序(对MapReduce的几种固定代码的理解)


    1.2MapReduce 和 HDFS 是如何工作的

    MapReduce 其实是两部分,先是 Map 过程,然后是 Reduce 过程。从词频计算来
    说,假设某个文件块里的一行文字是”Thisis a small cat. That is a smalldog.”,那
    么,Map 过程会对这一行进行处理,将每个单词从句子解析出来,依次生成形如
    <“this”,1>, <”is”, 1>, <”a”, 1>, <”small”, 1>,<”cat”, 1>, <”that”, 1>, <”
    is”, 1>,<”a”, 1>, <”small”, 1>, <”dog”,1>的键值对,<”this”,1>表示“this”
    这个单词出现了 1 次,在每个键值对里,单词出现的次数都是 1 次,允许有相同
    的键值对多次出现,比如<”is”,1>这个键值对出现了 2 次。Reduce 过程就是合
    并同类项,将上述产生的相同的键值对合并起来,将这些单词出现的次数累加起
    来,计算结果就是<“this”,1>, <”is”, 2>, <”a”, 2>, <”small”, 2>,<”cat”,

    1>, <”that”, 1>, <”dog”,1>。这种方式很简洁,并且可以进行多种形式的优化。
    比如说,在一个机器上,对本地存储的 1G 的文件块先 Map,然后再 Reduce,那
    么就得到了这 1G 的词频统计结果,然后再将这个结果传送到远程机器,跟其他
    999 台机器的统计结果再次进行 Reduce,就得到 1000G 文件的全部词频统计结
    果。如果文件没有那么大,只有三四个 G,就不需要在本地进行 Reduce 了,每
    次 Map 之后直接将结果传送到远程机器做 Reduce

    WordCount例子详细解析

    package org.apache.hadoop.examples;
    
    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.Reducer;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    /*
     * @author: 1605-1
     * @modify: 2019.9.3
     * @QQ 
     * **/
    public class WordCountTest {
    	//此阶段为分割数据 前两个泛型输入 后两个输出
    	public static class Map extends Mapper<Object , Text , Text , IntWritable>{  
    	    private static Text newKey=new Text();//新建输出为文本型输出 倒数第二个泛型
    	    private static final IntWritable one = new IntWritable(1);
    	    //第一个参数一般用不上 第二个参数为输入信息为文本 第三第四个参数 <”This”,1>
    	    public void map(Object key,Text value,Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException{  
    	    	String line=value.toString();  //读入数据
    		    System.out.println(line);//输出数据到控制台
    		    String[] array=line.split(" ");//把数据按照空格分割存为数组
    		    for(int i=0;i<array.length;i++) {
    		    	System.out.println(array[i]+"----map");//调试输出分割后的每个单词
    		    	newKey.set(array[i]);//往输出流文本添加数据
    		    	context.write(newKey, one);
    		    }
    		 }
    	}  
    	
    	//在reduce阶段,是map阶段分割后的经过排序后的数据向reduce任务中copy的过程,在此过程中会有一个背景线程将相同的key值进行合并,
    	//并将其value值归并到一个类似集合的容器中,此时的逻辑就是我们要遍历这个容器中的数据,计算它的值,然后输出
    	public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable>{  
    	    public void reduce(Text key,Iterable<IntWritable> values,Context context) throws IOException, InterruptedException{  
    	    	int num=0;  
    	    	//values <1><1,1>
    	    	//上面的key是上面的map传过来的 去重后的值应该是吧
    	        int count=0;  
    	        for(IntWritable val:values){  
    	        count++;  
    	        }  
    	        
    	        System.out.println("这是一个循环"+key);
    	        context.write(key,new IntWritable(count));  
    	        } 
    	 } 
    	
    	 public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException{  
    		 System.setProperty("hadoop.home.dir", "D:\Program Files\windowshadoop\hadoop-2.6.4");
    	        Configuration conf=new Configuration();  
    	        Path in=new Path("hdfs://192.168.1.101:9000/KETANGCESHI/CESHI/in/wordcount.txt");  
    	        Path out=new Path("hdfs://192.168.1.101:9000/KETANGCESHI/CESHI/out/outp1");  
    	        Job job =new Job(conf,"OneSort");  
    	        FileInputFormat.addInputPath(job,in);  
    	        FileOutputFormat.setOutputPath(job,out);  
    	        job.setJarByClass(WordCountTest.class);  
    	        job.setMapperClass(WordCountTest.Map.class);
    	        job.setReducerClass(WordCountTest.Reduce.class);
    	        job.setOutputKeyClass(Text.class);
    	        job.setOutputValueClass(IntWritable.class);
    	        job.waitForCompletion(true);
    	        System.exit(job.waitForCompletion(true) ? 0 : 1);  
    	        
    	        
    		 	
    	  } 
    
    }
    

      个人不理解的详细解析

    1  Text类从 hadoop 的 io 包里引入 Text 类。Text 类是存储字符串的可比较可序列化类(这个类用到很多个人感觉跟String 的区别为 这个可以序列化 至于序列化我也不知道是啥)

    2  public class XXXX  extends Mapper<Object, Text, Text,IntWritable>

    这四个泛型参数是什么  

    这里,第一个参数类型是 Object ,表示
    一般用不动 ,第二个参数参数类型是 Text,表示输入值的类型,第三
    个参数类型也是 Text,表示输出键类型,第四个参数类型是 IntWritable,表示输
    出值类型  (第一个好像不怎么用到 第二个是那个文本输入类型(你读入的文件) 第三第四个相当于 key 和value 了看你怎么用了)

    第一个参数再次解释

    第一个参数 Object 是 Hadoop 根据默认值生成的,一般是文件块
    里的一行文字的行偏移数,这些偏移数不重要,在处理时候一般用不上,第二个
    参数类型是要处理的字符串,形如”Thisis a cat.”。经过 Map 处理之后,输出
    的就是诸如<”This”,1>的键值对,这个”This”就是第三个参数类型,是 Text
    类型,而 1 就是第四个参数类型,是 IntWritable。

    关于那个wordcount IntWritableone = new IntWritable(1) 为什么 后面参数一直是1呢 ? 

    这个1 就是发现一个单词计数一次 假如是2的话发现一个单词就计数两次就不准确了

    Reducer 过程 大致解释

    1  public class XXXX extends Reducer<Text,IntWritable,Text,IntWritable>

    这个类继承 Hadoop 的 Reducer 类。
    这里的”<Text,IntWritable,Text,IntWritable>”,含义跟上一节一样,依次分别是
    输入键类型,输入值类型,输出键类型,输出值类型。

    2  public void reduce(Text key, Iterable<IntWritable> values,Context context) 

    重载的这个函数

    key 是输入键类型,values 是一个实现了 Iterable 接口的变量,
    可以把它理解成 values 里包含若干个 IntWritable 整数,可以通过迭代的方式遍
    历所有的值,至于 Context 类型,跟 Mapper 里的Context 类似的方式,是在 Redurer
    类内部实现的。
    举例来说,假如处理一个字符串”Thisis a That isa“,那么,经过 Map 过程之后,
    到达 reduce 函数的时候,依次传递给 reduce 函数的是:key=”This”,values=<1>;
    key= “is”,values=<1,1>;key = “a”,values=<1, 1>;key=”That”,values=<1>。
    注意,在 key= “is”和 key=”a”的时候,values 里有两个 1

    还有刚开始不懂得 那个map和reduce 相当于 读入一行 再操作(这个我没法说什么意思也许我不是这个意思  我这里输出了一下System.out.println("这是一个循环"+key); 自己理解一下吧)

    后面main函数 解释

    Configuration 类,顾名思义,读写和保存各种配置资源。
    2)“import org.apache.hadoop.fs.Path”
    引入 Path 类,Path 类保存文件或者目录的路径字符串。
    3)“import org.apache.hadoop.mapreduce.Job”
    引入 Job 类。在 hadoop 里,每个需要执行的任务是一个 Job,这个 Job 负责很多
    事情,包括参数配置,设置 MapReduce 细节,提交到 Hadoop 集群,执行控制,
    查询执行状态,等等。
    4)”importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat”
    引入 FileInputFormat 类。这个类的很重要的作用就是将文件进行切分 split,因为
    只有切分才可以并行处理。这个会在后面章节有详细解释。
    5)“import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat”
    引入 FileOutputFormat 类,处理结果写入输出文件。
    6)“import org.apache.hadoop.util.GenericOptionsParser”
    引入 GenericOptionsParser 类,这个类负责解析 hadoop 的命令行参数。
    7)”publicclass WordCount ”
    这是wordcount主类,它负责读取命令行参数,配置Job,调用Mapper和Reducer,
    返回结果等等工作。
    8)“Configurationconf = new Configuration()”
    默认情况下,Configuration 开始实例化的时候,会从 Hadoop 的配置文件里读取
    ————————————— ————————————————
    参数。
    9)”String[]otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs()”
    读取参数分两步,上一步是从 Hadoop 的配置文件读取参数,这一步是从命令行
    参数读取参数,args 是存放命令行参数的字符串数组。
    10)“if (otherArgs.length != 2) ”
    如果命令行参数不是 2 个,就出错了,退出。因为程序需要知道处理的是哪个输
    入文件,处理结果放到哪个目录,必须是两个参数。
    11)”Job job = new Job(conf, "wordcount")”
    每个运行的处理任务就是一个 Job,”worodcount”是 Job 的名字。
    12)“ job.setJarByClass(WordCount.class)”
    Jar 文件是 Java 语言的一个功能,可以将所有的类文件打包成一个 Jar 文件,
    setJarByClass 的意思是,根据 WordCount 类的位置设置 Jar 文件。
    13)“job.setMapperClass(TokenizerMapper.class)”
    设置 Mapper。
    14)“job.setReducerClass(IntSumReducer.class)”
    设置 Reducer。
    15)“job.setOutputKeyClass(Text.class)”
    设置输出键的类型。
    16)“job.setOutputValueClass(IntWritable.class)”
    设置输出值的类型。
    17)“FileInputFormat.addInputPath(job, new Path(otherArgs[0]))”
    设置要处理的文件,也就是输入文件,它是 otherArgs 的第一个参数。
    18)“FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]))”
    设置输出文件,将处理结果写到这个文件里,它是 otherArgs 的第二个参数。
    ————————————— ————————————————
    19)“System.exit(job.waitForCompletion(true) ? 0 : 1)”
    最后一步,job 开始执行,等待执行结束。

  • 相关阅读:
    [洛谷P3931]SAC E#1
    洛谷 P4127 [AHOI2009]同类分布 解题报告
    洛谷 P4475 巧克力王国 解题报告
    洛谷 P4148 简单题 解题报告
    洛谷 P2463 [SDOI2008]Sandy的卡片 解题报告
    洛谷 P4211 [LNOI2014]LCA 解题报告
    洛谷 P4074 [WC2013]糖果公园 解题报告
    AT1219 歴史の研究 解题报告
    洛谷 P4137 Rmq Problem /mex 解题报告
    THUWC2019 摸鱼记
  • 原文地址:https://www.cnblogs.com/xuexidememeda/p/11461420.html
Copyright © 2020-2023  润新知