大数据修炼之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

相关文章

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Python将大量遥感数据的值缩放指定倍数的方法(推荐)

《Python将大量遥感数据的值缩放指定倍数的方法(推荐)》本文介绍基于Python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处理,并将所得处理后数据保存为新的遥感影像... 本文介绍基于python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动