(超详细)MapReduce工作原理及基础编程

article/2025/10/16 17:49:47

MapReduce工作原理及基础编程(代码见文章后半部分) 

JunLeon——go big or go home


目录 

MapReduce工作原理及基础编程(代码见文章后半部分)

一、MapReduce概述

1、什么是MapReduce?

2、WordCount案例解析MapReduce计算过程

(1)运行hadoop自带的样例程序

(2)MapReduce工作过程

3、Shuffle过程详解

二、MapReduce编程基础

1、Hadoop数据类型

2、数据输入格式InputFormat

3、输入数据分块InputSplit和数据记录读入RecordReader

4、数据输出格式OutputFormat

5、数据记录输出类RecordWriter

 6、Mapper类

7、Reduce类

三、MapReduce项目案例

1、经典案例——WordCount

2、计算考试平均成绩

3、网站日志分析


 前言:

        Google于2003年在SOSP上发表了《The Google File System》,于2004年在OSDI上发表了《MapReduce: Simplified Data Processing on Large Clusters》,于2006年在OSDI上发表了《Bigtable: A Distributed Storage System for Structured Data》。这三篇论文为大数据及云计算的发展奠定了基础。

一、MapReduce概述

1、什么是MapReduce?

        MapReduce是一个分布式、并行处理的计算框架。

        MapReduce 把任务分为 Map 阶段和 Reduce 阶段。开发人员使用存储在HDFS 中数据(可实现快速存储),编写 Hadoop 的 MapReduce 任务。由于 MapReduce工作原理的特性, Hadoop 能以并行的方式访问数据,从而实现快速访问数据。

表1 map函数和rudece函数

函数输入输出说明
map

<k1,v1>

<0,helle world>

<12,hello hadoop>

List<k2,v2>

<hello,1>

<world,1>

<hello,1>

<hhadoop,1>

将获取到的数据集进一步解析成<key,value>,通过Map函数计算生成中间结果,进过shuffle处理后作为reduce的输入
reduce

<k2,List(v2)> 

<hadoop,1>

<hello,{1,1}>

<world,1>

<k3,v3>

<hadoop,1>

<hello,2>

<world,1>

reduce得到map输出的中间结果,合并计算将最终结果输出HDFS,其中List(v2),指同一k2的value

 MapReduce体系结构主要由四个部分组成,分别是:Client、JobTracker、TaskTracker以及Task

  1)Client

  用户编写的MapReduce程序通过Client提交到JobTracker端 用户可通过Client提供的一些接口查看作业运行状态。

  2)JobTracker

  JobTracker负责资源监控和作业调度 JobTracker 监控所有TaskTracker与Job的健康状况,一旦发现失败,就将相应的任务转移到其他节点 JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器(TaskScheduler),而调度器会在资源出现空闲时,选择合适的任务去使用这些资源。

  3)TaskTracker

  TaskTracker 会周期性地通过“心跳”将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等) TaskTracker 使用“slot”等量划分本节点上的资源量(CPU、内存等)。一个Task 获取到一个slot 后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。slot 分为Map slot 和Reduce slot 两种,分别供MapTask 和Reduce Task 使用。

  4)Task

  Task 分为Map Task 和Reduce Task 两种,均由TaskTracker 启动。

MapReduce各个执行阶段:

 MapReduce应用程序执行过程:

可以参考大佬黎先生的博客:MapReduce基本原理及应用 - 黎先生 - 博客园

2、WordCount案例解析MapReduce计算过程

(1)运行hadoop自带的样例程序

WordCount案例是一个经典案例,是Hadoop自带的样例程序。

作用:统计单词数量(出现的次数)

应用:求和、求平均值、求最值,

jar包存储在$HADOOP_HOME/share/hadoop/mapreduce/

$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.3.jar

例如:

 步骤:

1.在本地创建一个文件

输入以下内容:

2.上传到HDFS指定目录

在HDFS中创建指定文件:

 上传文件:

 3.使用hadoop jar命令运行jar程序,统计单词数量

 4.输出结果

执行部分过程:

 查看生成的文件:

 查看计算结果:

(2)MapReduce工作过程

        工作流程是Input从HDFS里面并行读取文本中的内容,经过MapReduce模型,最终把分析出来的结果用Output封装,持久化到HDFS中。

1.Mapper工作过程:

 附上Mapper阶段代码:

public static class WorldCount_Mapper extends Mapper<LongWritable, Text, Text, IntWritable>{@Overrideprotected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)throws IOException, InterruptedException {System.out.println("split:<" + key + ","+ value + ">" );String[] strs = value.toString().split(" ");for (String string : strs) {System.out.println("map:<" + key + ","+ value + ">" );context.write(new Text(string),new IntWritable(1));}}}

KEYIN--LongWritable:输入key类型,记录数据分片的偏移位置

VALUEIN—Text:输入的value类型,对应分片中的文本数据

KEYOUT--Text:输出的key类型,对应map方法中计算结果的key值

VALUEOUT—IntWritable:输出的value类型,对应map方法中计算结果的value值

        Mapper类从分片后传出的上下文中接收数据,数据以类型<LongWritable,Text>的键值对接收过来,通过重写map方法默认一行一行的读取数据并且以<key,value>形式进行遍历赋值。

2.Reducer工作过程:

 附上Reducer阶段代码:

public static class WorldCount_Reducer extends Reducer<Text, IntWritable, Text, IntWritable>{@Overrideprotected void reduce(Text key, Iterable<IntWritable> values,Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {int index  = 0;for (IntWritable intWritable : values) {System.out.println("reduce:<" + key + ","+ intWritable + ">" );index  += intWritable.get();}context.write(key,new IntWritable(index));}}

 Reducer任务继承Reducer类,主要接收的数据来自Map任务的输出,中间经过Shuffle分区、排序、分组,最终以<key,value>形式输出给用户。

Job提交代码:

public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {Job job = Job.getInstance();job.setJarByClass(WorldCount.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);job.setMapperClass(WorldCount_Mapper.class);job.setReducerClass(WorldCount_Reducer.class);FileInputFormat.addInputPath(job,new Path("hdfs://192.168.100.123:8020/input"));FileOutputFormat.setOutputPath(job, new Path("hdfs://192.168.100.123:8020/output"));job.waitForCompletion(true);}

       JobClients是用户提交的作业与ResourceManager交互的主要接口,JobClients提供提交作业、追踪进程、访问子任务的日志记录、获取的MapReduce集群状态信息等功能。

3、Shuffle过程详解

        Hadoop运行机制中,将map输出进行分区、分组、排序、和合并等处理后作为输入传给Reducer的过程,称为shuffle过程。

 shuffle阶段又可以分为Map端的shuffle和Reduce端的shuffle。

  一、Map端的shuffle

  写磁盘:Map端会处理输入数据并产生中间结果,这个中间结果会写到本地磁盘,而不是HDFS。每个Map的输出会先写到内存缓冲区中,当写入的数据达到设定的阈值时,系统将会启动一个线程将缓冲区的数据写到磁盘,这个过程叫做spill。

  分区、分组、排序:在spill写入之前,会先进行二次排序,首先根据数据所属的partition进行排序,然后每个分区(partition)中的数据再按key来排序。partition的目是将记录划分到不同的Reducer上去,以期望能够达到负载均衡,以后的Reducer就会根据partition来读取自己对应的数据。接着运行combiner(如果设置了的话),combiner的本质也是一个Reducer,其目的是对将要写入到磁盘上的文件先进行一次处理,这样,写入到磁盘的数据量就会减少。最后将数据写到本地磁盘产生spill文件(spill文件保存在{mapred.local.dir}指定的目录中,Map任务结束后就会被删除)。

        文件合并:最后,每个Map任务可能产生多个溢写文件(spill file),在每个Map任务完成前,会通过多路归并算法将这些spill文件归并成一个已经分区和排序的输出文件。至此,Map的shuffle过程就结束了。

        压缩:在shuffle过程中如果压缩被启用,在map传出数据传入Reduce之前可执行压缩,默认情况下压缩是关闭的,可以将mapred.compress.map.output设置为true可实现压缩。

  二、Reduce端的shuffle

  Reduce端的shuffle主要包括三个阶段,copysort(merge)和reduce

  首先要将Map端产生的输出文件拷贝到Reduce端,但每个Reducer如何知道自己应该处理哪些数据呢?因为Map端进行partition的时候,实际上就相当于指定了每个Reducer要处理的数据(partition就对应了Reducer),所以Reducer在拷贝数据的时候只需拷贝与自己对应的partition中的数据即可。每个Reducer会处理一个或者多个partition,但需要先将自己对应的partition中的数据从每个Map的输出结果中拷贝过来。

        接下来就是排序(sort)阶段,也成为合并(merge)阶段,因为这个阶段的主要工作是执行了归并排序。从Map端拷贝到Reduce端的数据都是有序的,所以很适合归并排序。最终在Reduce端生成一个较大的文件作为Reduce的输入。MapReduce编程接口

二、MapReduce编程基础

1、Hadoop数据类型

        Hadoop数据包括:BooleanWritable、ByteWritable、DoubleWritable、FloatWritale、IntWritable、LongWritable、Text、NullWritable等,它们实现了WritableComparable接口。其中Text表示使用UTF8格式存储的文本、NullWritable类型是当(key,value)中的key或value为空时使用。

表2 Hadoop Writable与Java数据类型参照表

Java基本类型Writable封装类类型序列化后的长度为
booleanBooleanWritable布尔型1
byteByteWritable字节型1
doubleDoubleWritable双精度浮点型8
floatFloatWritable单精度浮点型8
int

IntWritable


VIntWritable

整型

4


1-5

long

LongWritable

长整型8
shortShortWritable短整型2
nullNullWritable空值0
Text文本类型

        除了上述Hadoop类型外,用户还可以自定义新的数据类型。用户自定义数据类型需要实现Writable接口,但如果需要作为主键key使用或需要比较大小时,则需要实现WritableComparable接口。

2、数据输入格式InputFormat

抽象类InputFormat<K,V>有三个直接子类:

        FileInputFormat<K,V>、DBInputFormat<T>、DelegatingInputFormat<K,V>

其中,文件输入格式类FileInputFormat<K,V>类有几个子类:

        TextInputFormat、KeyValueInputFormat、SequenceFileInputFormat<K,V>、NlineInputFormat、CombineFileInputFormat<K,V>

序列化文件输入类SequenceFileInputFormat<K,V>有几个子类:

        SequenceFileAsBinaryInputFormat、SequenceFileAsTextInputFormat、SequenceFileInputFilter<K,V>

数据库输入格式类DBInputFormat<T>的直接子类是:DataDriverDBInputFormat<T>,而这个子类又派生子类:OracleDataDriverDBInputFormat<T>

表3  常用数据输入格式类

InputFormat类描述键(Key)值(Value)
TextInputFormat默认输入格式,读取文本文件的行当前行的偏移量当前行内容
KeyValueTextInputFormat将行解析成键值对行内首个制表符的内容行内其余内容
SequenceFileInputFormat专用于高性能的二进制格式用户定义用户定义

3、输入数据分块InputSplit和数据记录读入RecordReader

        编程时由用户选择的数据输入格式InputFormat类型来自动决定数据分块InputSplit和数据记录RecordReader类型。一个InputSplit将单独作为一个Mapper的输入,即作业的Mapper数量是由InputSplit个数决定的。

表4 数据输出格式类对应的Reader类型

InputFormat类RecordReader类描述
TextInputFormatLineRecordReader读取文本文件的行
KeyValueTextInputFormatKeyValueLineRecordReader读取行并将行解析为键值对
SequenceFileInputFormatSequenceFileRecordReader用户定义的格式产生键与值
DBInputFormatDBRecordReader仅适合读取少量数据记录,不适合数据仓库联机数据分析大量数据的读取处理

4、数据输出格式OutputFormat

抽象类OutputFormat<K,V>有四个直接子类:

        FileOutputFormat<K,V>、DBOutputFormat<K,V>、NullOutputFormat<K,V>、FilterOutputFormat<K,V>

FileOutputFormat<K,V>有两个直接子类:

        TextOutputFormat<K,V>、SequenceFileOutputFormat<K,V>

SequenceFileOutputFormat<K,V>有直接子类:SequenceFileAsBinaryOutputFormat

FilterOutputFormat<K,V>有直接子类:LazyOutputFormat<K,V>

5、数据记录输出类RecordWriter

数据记录输出类RecordWriter是一个抽象类。

表5 数据输出格式类对应的数据记录Writer类型

OutputFormat类RecordWriter类描述
TextOutputFormatLineRecordWriter将结果数据以“key + \t + value”形式输出到文本文件中
SequenceFileOutputFormatSequenceFileRecordWriter用户定义的格式产生键与值
DBOutputFormatDBRecordWriter将结果写入到一个数据库表中
FilterOutputFormatFilterRecordWriter对应于过滤器输出模式的数据记录模式,只将过滤器的结果输出到文件中

 6、Mapper类

        Mapper类是一个抽象类,位于hadoop-mapreduce-client-core-2.x.x.jar中,其完整类名是:org.apache.hadoop.mapreduce.Mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>,需派生子类使用,在子类中重写map方法:map(KEYIN key,VALUEIN value,Mapper.Context context)对出入的数据分块每个键值对调用一次。

7、Reduce类

        Reduce类是一个抽象类,位于hadoop-mapreduce-client-core-2.x.x.jar中,其完整类名是:org.apache.hadoop.mapreduce.Reduce<KEYIN,VALUEIN,KEYOUT,VALUEOUT>,需派生子类使用,在子类中重写reduce方法:reduce(KEYIN key,Inerable <VALUEIN> value,Reducer.Context context)对出入的数据分块每个键值对调用一次。

三、MapReduce项目案例

1、经典案例——WordCount

代码演示:

package hadoop.mapreduce;import java.io.IOException;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.LongWritable;
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;public class MyWordCount {/** 	KEYIN:是map阶段输入的key(偏移量)* 	VALUEIN:是map阶段输入的value(文本文件的内容--行)*  KEYOUT:是map阶段输出的key(单词)*  VALUEOUT:是map阶段输出的value(单词的计数--1)*  *  Java基本数据类型:*  	int、short、long、double、float、char、boolean、byte*  hadoop数据类型*  	IntWritable、ShortWritable、LongWritable、DoubleWritable、FloatWritable*  	ByteWritable、BooleanWritable、NullWritable、Text*  	Text:使用utf8编码的文本类型*/public static class WordCount_Mapper extends Mapper<LongWritable, Text, Text, IntWritable>{@Override	//方法的重写protected void map(LongWritable key, Text value, Mapper<LongWritable, Text,Text, IntWritable>.Context context)throws IOException, InterruptedException {String[] line = value.toString().split(" ");	//将获取到的数据以空格进行切分成一个个单词for (String word : line) { 	//遍历单词的数组context.write(new Text(word), new IntWritable(1));  //单词进行计数,将中间结果写入context}}												}/** KEYIN:reduce阶段输入的key(单词)* VALUEIN:reduce阶段输入的value(单词的计数)* KEYOUT:reduce阶段输出的key(单词)* VALUEOUT:reduce阶段输出的value(单词计数的总和)* * reduce方法中做以下修改:* 	将Text arg0改为Text key*  将Iterable<IntWritable> arg1改为Iterable<IntWritable> value*  将Context arg2修改为Context context*/public static class WordCount_Reducer extends Reducer<Text, IntWritable, Text, IntWritable>{@Overrideprotected void reduce(Text key, Iterable<IntWritable> values,Reducer<Text, IntWritable, Text, IntWritable>.Context context)throws IOException, InterruptedException {int sum = 0;	//创建一个变量,和for (IntWritable intWritable : values) {		//遍历相同key单词的计数sum += intWritable.get();	//将相同key单词的计数进行累加}context.write(key, new IntWritable(sum));	//将计算的结果写入context}}//提交工作public static void main(String[] args) throws Exception {String inPath= "hdfs://192.168.182.10:8020/input.txt";String outPath = "hdfs://192.168.182.10:8020/output/";Configuration conf = new Configuration();Job job = Job.getInstance();	//创建Job对象jobFileSystem fs = FileSystem.get(conf);if (fs.exists(new Path(outPath))) {fs.delete(new Path(outPath), true);}job.setJarByClass(MyWordCount.class); 	//设置运行的主类MyWordCountjob.setMapperClass(WordCount_Mapper.class); 	//设置Mapper的主类job.setReducerClass(WordCount_Reducer.class); 	//设置Reduce的主类job.setOutputKeyClass(Text.class); 	//设置输出key的类型job.setOutputValueClass(IntWritable.class); 	//设置输出value的类型//设置文件的输入路径(根据自己的IP和HDFS地址设置)FileInputFormat.addInputPath(job, new Path(inPath));	//设置计算结果的输出路径(根据自己的IP和HDFS地址设置)FileOutputFormat.setOutputPath(job, new Path(outPath));System.exit((job.waitForCompletion(true)?0:1)); 	//提交任务并等待任务完成}
}

打包上传虚拟机:

步骤:

右键单击项目名 --> 选择 Export --> Java --> JAR file --> Browse...选择存放路径 --> 文件名

命名为wordcount.jar,将打包好的jar包上传到虚拟机中

运行代码:

在本地创建一个文件input.txt

vi input.txt

 添加内容:

hello world
hello hadoop
bye world
bye hadoop

上传到DHFS中:

hadoop fs -put input.txt /

使用jar命令执行项目:

hadoop jar wordcount.jar hadoop.mapreduce.MyWordCount

如下图:

查看结果: 

2、计算考试平均成绩

代码演示:

Mapper类

package hadoop.mapreduce;import java.io.IOException;
import java.util.StringTokenizer;import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.Mapper;/** 编写CourseScoreAverageMapper继承Mapper类*/
public class CourseScoreAverageMapper extends Mapper<LongWritable, Text, Text, IntWritable>{@Override	//方法的重写protected void map(LongWritable key, Text value, Mapper<LongWritable, Text,Text, IntWritable>.Context context)throws IOException, InterruptedException {String line = new String(value.getBytes(),0,value.getLength(),"UTF8");	//转换中文编码Counter countPrint =  context.getCounter("CourseScoreAverageMapper.Map 输出传递Value:", line);	//通过计数器输出变量值countPrint.increment(1L);	//将计数器加一StringTokenizer tokenArticle = new StringTokenizer(line,"\n");	//将输入的数据按行“\n”进行分割while(tokenArticle.hasMoreElements()) {StringTokenizer tokenLine = new StringTokenizer(tokenArticle.nextToken());	//每行按空格划分String strName = tokenLine.nextToken();		//按空格划分出学生姓名String strScore = tokenLine.nextToken();	//按空格划分出学生成绩Text name = new Text(strName);	//转换为Text类型int scoreInt = Integer.parseInt(strScore);	//转换为int类型context.write(name, new IntWritable(scoreInt));		//将中间结果写入contextcountPrint = context.getCounter("CourseScoreAverageMapper.Map中循环输出信息:", "<key,value>:<"+strName+","+strScore+">");	//输出信息countPrint.increment(1L);	//将计数器加一}}												
}

Reducer类

package hadoop.mapreduce;import java.io.IOException;import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.Reducer;/** 编写CourseScoreAverageReducer继承Reduce类*/
public class CourseScoreAverageReducer extends Reducer<Text, IntWritable, Text, IntWritable>{@Override  //重写reduce方法protected void reduce(Text key, Iterable<IntWritable> values,Reducer<Text, IntWritable, Text, IntWritable>.Context context)throws IOException, InterruptedException {int sum = 0;	//总分int count = 0;	//科目数for (IntWritable val : values) {		//遍历相同key的分数sum += val.get();	//将相同key的分数进行累加count++;	//计算科目数}int average = (int)sum/count;	//计算平均分context.write(key, new IntWritable(average));	//将计算的结果写入contextCounter countPrint = context.getCounter("CourseScoreAverageReducer.Reducer中输出信息:", "<key,value>:<"+key.toString()+","+average+">");	//输出信息countPrint.increment(1L);	//计数器加1}
}

Driver类

package hadoop.mapreduce;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.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;public class CourseScoreDriver {public static void main(String[] args) throws Exception {Configuration conf = new Configuration();	//获取配置文件Job job = Job.getInstance(conf,"CourseScoreAverage");	//创建Job对象jobString[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();	//获取命令行参数if(otherArgs.length<2) {	System.err.print("Usage:hadoop jar MyAverage.jar <in> <out> ");System.err.print("hadoop jar MyAverage.jar hadoop.mapreduce.CourseScoreDriver <in> <out>");System.exit(2);}else {for (int i = 0; i < otherArgs.length-1; i++) {	//设置文件输入路径if(!("hadoop.mapreduce.CourseScoreDriver".equalsIgnoreCase(otherArgs[i]))) {  //排除hadoop.mapreduce.CourseScoreDriver这个参数FileInputFormat.addInputPath(job, new Path(otherArgs[i]));System.out.println("参数IN:"+otherArgs[i]);}}//设置文件输出路径FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length-1]));  //设置输出路径System.out.println("参数OUT:"+otherArgs[otherArgs.length-1]);}FileSystem hdfs = FileSystem.get(conf);	//创建文件系统if(hdfs.exists(new Path(otherArgs[otherArgs.length-1]))) {	//如果已经存在该路径,则删除该路径hdfs.delete(new Path(otherArgs[otherArgs.length-1]), true);}job.setJarByClass(CourseScoreDriver.class); 	//设置运行的主类CourseScoreDriverjob.setMapperClass(CourseScoreAverageMapper.class); 	//设置Mapper的主类job.setCombinerClass(CourseScoreAverageReducer.class); 	//设置Combiner的主类job.setReducerClass(CourseScoreAverageReducer.class); 	//设置Reduce的主类job.setOutputKeyClass(Text.class); 	//设置输出key的类型job.setOutputValueClass(IntWritable.class); 	//设置输出value的类型job.setInputFormatClass(TextInputFormat.class);		//设置输入格式job.setOutputFormatClass(TextOutputFormat.class);	//设置输出格式System.exit((job.waitForCompletion(true)?0:1)); 	//提交任务并等待任务完成System.out.println("Job Finished!");}
}

打包上传虚拟机:

步骤:

右键单击项目名 --> 选择 Export --> Java --> JAR file --> Browse...选择存放路径 --> 文件名

命名为average.jar , 将打包好的average.jar上传到虚拟机中

运行代码:

首先准备三个文件 Chinese.txt、Math.txt、English.txt,添加如下内容:

 将文件上传到HDFS的data目录下: 

hadoop fs -mkdir /data
hadoop fs -put Chinese.txt /data/
hadoop fs -put Math.txt /data/
hadoop fs -put English.txt /data/

执行代码:

hadoop jar average.jar hadoop.mapreduce.CourseScoreDriver /data /data/output

 查看结果,如下图:

3、网站日志分析

代码演示:

打包上传虚拟机:

运行代码:


http://chatgpt.dhexx.cn/article/By3Z4lBd.shtml

相关文章

【小白视角】大数据基础实践(五) MapReduce编程基础操作

目录 1. MapReduce 简介1.1 起源1.2 模型简介1.3 MRv1体系结构1.4 YARN1.4.1 YARN体系结构1.4.2 YARN工作流程 2. MapReduce 工作流程3. Java Api要点4. 实验过程最后 1. MapReduce 简介 1.1 起源 在函数式语言里&#xff0c;map表示对一个列表&#xff08;List&#xff09;中…

MapReduce编程

一、MapReduce编程规范 MapReduce的开发一共又八个步骤&#xff0c;其中Map阶段分为2个步骤&#xff0c;Shuffle阶段4个步骤&#xff0c;Reduce阶段分为2个步骤。 1.1 步骤流程 Map阶段2个步骤 设置InputFormat类&#xff0c;将数据切分为key-value&#xff08;k1和v1&#x…

SSL/TLS

SSL/TLS 一、SSL/TLS1.1 历史发展1.2 使用场景1.3 解决的问题1.4 工作流程 二、对称加密&#xff08;Symmetric Cryptography&#xff09;2.1 工作原理2.2 翻转攻击2.3 认证加密&#xff08;Authentication Encryption&#xff09;2.4 Diffie-Hellman2.5 KDF2.6 Diffie-Hellman…

HTTPS,SSL,TLS

SSL TLS secure sockets layer 安全套接字层&#xff0c;Netscape公司研发。 transport layer security 安全传输层协议 定义 协议 年份 SSL 1.0 未知 SSL 2.0 1995 SSL 3.0 1996 TLS 1.0 1999 TLS 1.1 2006 TLS 1.2 2008 TLS 1.3 2018 IETF&#xff08;The…

TLS传输协议

TLS&#xff1a;安全传输层协议&#xff08;TLS&#xff09;用于在两个通信应用程序之间提供保密性和数据完整性。 该协议由两层组成&#xff1a;TLS 记录协议&#xff08;TLS Record&#xff09;和 TLS 握手协议&#xff08;TLS Handshake&#xff09;。 传输层安全性协议&a…

LVGL misc tlsf算法(lv_tlsf.c)

更多源码分析请访问:LVGL 源码分析大全 目录 1、概述2、算法特点3、同类型算法举例1、概述 LVGL采用的内存分配器是使用的tlsf算法。因为这个算法只是一个实时系统常用的算法,可以看作是一个工具,对LVGL本身并没有逻辑上的关联,所以这里只介绍一下算法的基本知识,就不过…

TLS/SSL 协议详解(17) Certificate verify

发送这个类型的握手需要2个前提条件 &#xff08;1&#xff09;&#xff1a;服务器端请求了客户端证书 &#xff08;2&#xff09;&#xff1a;客户端发送了非0长的证书 此时&#xff0c;客户端想要证明自己拥有该证书&#xff0c;必然需要私钥签名一段数据发给服务器验证。 …

HTTPS之TLS证书

文章目录 一. TLS概述1. TLS概述2. HTTPS 协议栈与 HTTP 的唯一区别3. TLS协议版本 二. TLS证书格式1. 概述2. 示例&#xff1a;知乎网站证书解析(mac系统)3. 通过openssl获取证书的含义 三. 证书链&#xff08;Certificate Chain&#xff09;1. 背景2. 概述3. 背景问题的解释 …

SSL和TLS简单概述

SSL和TLS简单概述 本文不会只有几个比较重要的概念,科普性质的文章,方便自己记忆,极大概率存在缺陷 如果想了解这方面的内容&#xff0c;请参阅官方文档。 SSL和TLS TLS是更安全版本的ssl,先出的的ssh,一个基于加密机制的应用,之后为了方便给其他应用层使用然后引入了ssl,最…

动态内存管理——tlsf

定义 TLSF(全称Two-Level Segregated Fit) 源码 https://github.com/mattconte/tlsf 代码 结构体 typedef struct block_header_t {/* 指向上一个物理块。*/struct block_header_t * prev_phys_block;/* 此块的大小&#xff0c;不包括块头。*/size_t size;/* 下一个和上一…

SSL与TLS协议详解

写在最前面的话&#xff1a;这篇文章是我借鉴了Eric Rescorla的《SSL and TLS》一书之后对该书的前半部分内容整合而做。如您需要开发围绕SSL、TLS的程序建议参阅原著或者RFC相关文档。 一、关于SSL、TLS与HTTPS的三两事 什么是SSL、TLS&#xff1a; 众所周知&#xff0c;真…

TLS协议/SSL协议

历史背景 SSL(Secure Socket Layer 安全套接层)是基于HTTPS下的一个协议加密层&#xff0c;最初是由网景公司&#xff08;Netscape&#xff09;研发&#xff0c;后被IETF&#xff08;The Internet Engineering Task Force - 互联网工程任务组&#xff09;标准化后写入&#xf…

TLS加密体系

谈到这个词&#xff0c;可能大家的第一印象就是加密&#xff0c;而对TLS了解甚少。那么在介绍 TLS 加密体系之前先来讲一讲加密。 一提到加密&#xff0c;可能很多人脑海中会浮现出电视剧里特务的场景&#xff0c;他们拿出一台电报机&#xff0c;“滴滴滴滴”按下情报报文&…

TLS概述

握手过程 可分为5步&#xff08;使用Diffie – Hellman算法&#xff09;&#xff1a; 第一步&#xff0c;浏览器给出协议版本号、一个客户端生成的随机数&#xff08;Client random&#xff09;&#xff0c;以及客户端支持的加密方法。 第二步&#xff0c;服务器确认双方使用的…

SSL与DTLS简介

目录 SSL简介 DTLS-基于UDP的TLS 记录层 传输层映射 早期我们在访问web时使用HTTP协议&#xff0c;该协议在传输数据时使用明文传输&#xff0c;会带来了以下风险&#xff1a; 信息窃听风险&#xff0c;第三方可以获取通信内容&#xff1b; 信息篡改风险&#xff0c;第三方…

TLS/SSL 协议

TLS/SSL 协议的工作原理 TLS/SSL 协议的工作原理 • 身份验证 • 保密性 • 完整 TLS/SSL 发展 TLS 协议 • Record 记录协议 • 对称加密 • Handshake 握手协议 • 验证通讯双方的身份 • 交换加解密的安全套件 • 协商加密参 TLS 安全密码套件解 对称加密的工作原理&am…

SSL/TLS详解

SSL/TLS详解 1. 前言 ​ 我们都知道Https就是加密协议中采用了SSL/TLS协议&#xff0c;这是面试常客&#xff0c;如果被问到了&#xff0c;你懂的越多&#xff0c;答得越深&#xff0c;你的面评相应来说也就会越高&#xff0c;对于SSL/TLS&#xff0c;我们不仅仅要知道其为数…

TLS协议简单介绍

TLS简介 介绍 TLS&#xff08;Transport Layer Security&#xff09;即安全传输层协议&#xff0c;在两个通信应用程序之间提供保密性和数据完整性。最典型的应用就是HTTPS。HTTPS&#xff0c;即HTTP over TLS&#xff0c;就是安全的HTTP&#xff0c;运行在HTTP层之下&#x…

esp-idf的内存管理——tlsf之上的封装

目录 1 为什么要封装2 先看结构2.1 multi heapnote1note2 2.2 heap caps2.3 层次关系 3 再看接口3.1 内存的申请3.2 内存的释放3.2 堆完整性检测3.3 其它 参考 1 为什么要封装 封装通常会降低效率&#xff0c;但能够带来诸如通用性提升等好处&#xff0c;idf在tlsf的基础上增加…

SSL/TLS 证书管理

SSL 证书发现 随着组织的 IT 基础架构的扩展&#xff0c;他们为每台计算机获取证书以保护其资源和域。此外&#xff0c;开发人员通常会创建许多自签名证书&#xff0c;以便在产品的开发阶段保护内部网络。组织通常最终会拥有数千个证书。自动发现证书提供了对证书基础结构的完…