大数据修炼之hadoop--MapReduce

2024-09-02 12:32
文章标签 数据 hadoop 修炼 mapreduce

本文主要是介绍大数据修炼之hadoop--MapReduce,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 定义
  • 概念
  • 流程
  • 支持的数据类型
  • demo
  • 切片策略
    • FileInputFormat
  • 片与块的关系
  • 提交流程
  • 关键设置
  • Job提交流程阶段总结
    • 准备
    • 提交

定义

MapReduce最早是由谷歌公司研究提出的一种面向大规模数据处理的并行计算模型和方法。
特点:
MapReduce是一个基于集群的高性能并行计算平台。
MapReduce是一个并行计算与运行软件框架。
MapReduce是一个并行程序设计模型与方法。

易于编程,良好的扩展性,高容错性,适合PB级别以上的海量数据的离线处理
但是同时,不适合实时计算,不擅长流式计算,不擅长DAG计算(程序依赖)

概念

Job(任务): 一个MR程序
MRAppMaster(MR任务的主节点):一个Job在运行是,会先启动一个进程,负责Job执行过程的监控,容错,申请资源,提交task
Task(任务):计算
Map:切分。 将输入数据切分成若干小部分,每个部分为1片split,每片数据交给一个task进行计算(MapTask)
Reduce: MapTask的汇总

常用组件:
Mapper
Reducer
InputFormat 输入目录的文件格式。 普通文件:FileInputFormat , SequeceFileInput(hadoop格式),DBInputFormat(数据库的格式)
OutputFormat 类上
RecordWriter 记录写出其 结果以什么格式,写出到文件中
Partitioner 分区器

流程

MapReduce中,Map阶段处理的数据如何传递给Reduce阶段,是整个MapReduce框架中最关键的一个流程,这个流程就叫Shuffle。它的核心机制包括数据分区、排序和缓存等。
在这里插入图片描述

支持的数据类型

(1)BooleanWritable:标准布尔型数值。
(2)ByteWritable:单字节数值。
(3)DoubleWritable:双字节数。
(4)FloatWritable:浮点数。
(5)IntWritable:整型数。
(6)LongWritable:长整型数。
(7)Text:使用UTF8格式存储的文本。
(8)NullWritable:当<key,value>中的key或value为空时使用。
(9)ArrayWritable:存储属于Writable类型的值数组(要使用ArrayWritable类型作为Reduce输入的value类型,需要创建ArrayWritable的子类来指定存储在其中的Writable值的类型)。

运行最新版hadoop的mapreduce的时候经常会有各种报错,最好是有linux环境可以用。windows环境下设置HADOOP_HOME,并把wintils放在bin目录下:
https://github.com/steveloughran/winutils

demo

maven

 <dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-core</artifactId><version>3.2.0</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>

code:

public class MyDriver {public static final Configuration configuration = new Configuration();static {
//        configuration.set("fs.defaultFS", "hdfs://192.168.31.101:9000");System.setProperty("HADOOP_USER_NAME", "hadoop");
//        System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");}public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {remortJob();
//        localJob();}private static void remortJob() throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");Path inputPath=new Path("/wcinput/logs");Path outputPath=new Path("/wcoutput/test");configuration.set("fs.defaultFS","hdfs://192.168.31.101:9000");configuration.set("fs.defaultFS","hdfs://192.168.31.101:9000");FileSystem fs=FileSystem.get(new URI("hdfs://192.168.31.101:9000"),configuration,"root");if (fs.exists(outputPath)) {fs.delete(outputPath, true);}
//        创建jobJob job=Job.getInstance(configuration);job.setJobName("wordcount test");
//        设置jobjob.setMapperClass(MyMapper.class);job.setReducerClass(MyReducer.class);
//            准备序列化器job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);//            输入输出目录FileInputFormat.setInputPaths(job,inputPath);FileOutputFormat.setOutputPath(job,outputPath);
//        运行jobjob.waitForCompletion(true);}private static void localJob() throws IOException, InterruptedException, ClassNotFoundException {System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");Path inputPath=new Path("d:/mrinput/");Path outputPath=new Path("d:/mroutput/wd");FileSystem fs=FileSystem.get(configuration);
//        创建jobJob job=Job.getInstance(configuration);job.setJobName("wordcount test");
//        设置jobjob.setMapperClass(MyMapper.class);job.setReducerClass(MyReducer.class);
//            准备序列化器job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);//            输入输出目录FileInputFormat.setInputPaths(job,inputPath);FileOutputFormat.setOutputPath(job,outputPath);
//        运行jobjob.waitForCompletion(true);}
}public class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable> {private Text outKey=new Text();private IntWritable outValue=new IntWritable(1);/*** 每个 keyin  valuein 执行一次* 每个 keyvalue都转成(word,1)* @param key* @param value* @param context* @throws IOException* @throws InterruptedException*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//        super.map(key, value, context);System.out.println(" key:"+key +"  value:"+value);String[] split = value.toString().split("\t");for (String word :split) {outKey.set(word);context.write(outKey,outValue);}}
}public class MyReducer extends Reducer<Text, IntWritable,Text,IntWritable> {private IntWritable outValue;@Overrideprotected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//        super.reduce(key, values, context);int sum=0;for (IntWritable item :values) {sum += item.get();}outValue = new IntWritable(sum);context.write(key,outValue);}
}

InputFormat的作用:

  1. 验证输入目录中文件格式,是否符合当前Job的要求
  2. 生产切片,每个切片都会交给一个MapTask处理
  3. 提供RecordReader,由RR从切片中读取记录,交给Mapper处理。

方法 List getSplits: 切片
RecordReader<K,V> createRecordReader: 创建RR

默认使用的是TextInputFormat , LineRecordReader

切片策略

TextInputFormat:
常用于输入目录中全是文本文件
RecordReader: LineRecordReader 一次处理一行,将一行内容偏移量作为key,内容value

NLineInputFormat:
切分n行,执行逻辑复杂情况

KeyValueTextInputFormat:
键值对格式
CombineTextInputText:
多个小文件

FileInputFormat

 public List<InputSplit> getSplits(JobContext job) throws IOException {StopWatch sw = new StopWatch().start();long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));// getFormatMinSplitSize  其实是1,getMinSplitSize 是取配置 mapreduce.input.fileinputformat.split.maxsizelong maxSize = getMaxSplitSize(job);   //mapreduce.input.fileinputformat.split.maxsize// generate splitsList<InputSplit> splits = new ArrayList<InputSplit>();List<FileStatus> files = listStatus(job);  // 输入目录所有文件的状态信息boolean ignoreDirs = !getInputDirRecursive(job)&& job.getConfiguration().getBoolean(INPUT_DIR_NONRECURSIVE_IGNORE_SUBDIRS, false);for (FileStatus file: files) {if (ignoreDirs && file.isDirectory()) {continue;}Path path = file.getPath();long length = file.getLen();if (length != 0) {BlockLocation[] blkLocations;if (file instanceof LocatedFileStatus) {blkLocations = ((LocatedFileStatus) file).getBlockLocations();} else {FileSystem fs = path.getFileSystem(job.getConfiguration());blkLocations = fs.getFileBlockLocations(file, 0, length);}if (isSplitable(job, path)) {//  判断方法与实现类相关,各个类自己实现,默认truelong blockSize = file.getBlockSize();long splitSize = computeSplitSize(blockSize, minSize, maxSize);long bytesRemaining = length; // 循环切片while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);splits.add(makeSplit(path, length-bytesRemaining, splitSize,blkLocations[blkIndex].getHosts(),blkLocations[blkIndex].getCachedHosts()));bytesRemaining -= splitSize;}if (bytesRemaining != 0) {int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,blkLocations[blkIndex].getHosts(),blkLocations[blkIndex].getCachedHosts()));}} else { // not splitable  不可切,直接传入文件if (LOG.isDebugEnabled()) {// Log only if the file is big enough to be splittedif (length > Math.min(file.getBlockSize(), minSize)) {LOG.debug("File is not splittable so no parallelization "+ "is possible: " + file.getPath());}}splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),blkLocations[0].getCachedHosts()));}} else { //Create empty hosts array for zero length filessplits.add(makeSplit(path, 0, length, new String[0]));}}// Save the number of input files for metrics/loadgenjob.getConfiguration().setLong(NUM_INPUT_FILES, files.size());sw.stop();if (LOG.isDebugEnabled()) {LOG.debug("Total # of splits generated by getSplits: " + splits.size()+ ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));}return splits;}

片与块的关系

默认的片大小是文件的块大小,文件默认128M
片: InputSplit 计算MR时进行切片,临时的逻辑区,与输入格式相关
块:Block HDFS的存储单位,实际物理存在

建议,片大小=块大小。减少磁盘IO,网络IO

提交流程

 public boolean waitForCompletion(boolean verbose) throws IOException, InterruptedException,ClassNotFoundException {if (state == JobState.DEFINE) {submit();}if (verbose) {monitorAndPrintJob();} else {// get the completion poll interval from the client.int completionPollIntervalMillis = Job.getCompletionPollInterval(cluster.getConf());while (!isComplete()) {try {Thread.sleep(completionPollIntervalMillis);} catch (InterruptedException ie) {}}}return isSuccessful();}
 public void submit() throws IOException, InterruptedException, ClassNotFoundException {ensureState(JobState.DEFINE);setUseNewAPI();connect();final JobSubmitter submitter = getJobSubmitter(cluster.getFileSystem(), cluster.getClient());status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {public JobStatus run() throws IOException, InterruptedException, ClassNotFoundException {return submitter.submitJobInternal(Job.this, cluster);}});state = JobState.RUNNING;LOG.info("The url to track the job: " + getTrackingURL());}

关键设置

MapTask数量,认为设置无效,只能通过切片的方式设置,MapTask取决于切片数。

Job提交流程阶段总结

准备

运行job.waitForCompletion(),生成一下信息
job.split 当前job的切片信息,有几个切片对象
job.splitmetainfo 切片对象的属性信息
job.xml job的属性配置

提交

本地模式:LocalJobRunner提交,创建LocalJobRunner.Job()
Map阶段: 线程池,提交多个MapTaskRunnable
每个MapTaskRunnable线程上,实例化一个MapTask对象
每个MapTask对象实例化一个Mapper
线程运行结束,在线程的作业目录中生成file.out文件,报错MapTask输出的所有Key-value
map:使用RR将切片中的数据读入到Mapper.map() context.write(key,value)
Reduce阶段:
线程池提交多个ReduceTaskRunnable
每个ReduceTask对象,实例化一个Reducer, reducer.run()
线程运行结束,在输出目录中生成,part-r-000x文件,保存ReduceTask输出的所有Key-value
copy: shuffle线程拷贝MapTask指定的分区数据
sort:将拷贝的所有分区数据汇总后,排序
reduce:排好序的数据,进行 合并

这篇关于大数据修炼之hadoop--MapReduce的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129958

相关文章

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个

SpringBoot整合jasypt实现重要数据加密

《SpringBoot整合jasypt实现重要数据加密》Jasypt是一个专注于简化Java加密操作的开源工具,:本文主要介绍详细介绍了如何使用jasypt实现重要数据加密,感兴趣的小伙伴可... 目录jasypt简介 jasypt的优点SpringBoot使用jasypt创建mapper接口配置文件加密

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.