MapReduce 思想

MapReduce 是 Google 提出的一个软件架构,用于大规模数据集的并行运算。概率“Map(映射)”和“Reduce(归约)”以及它们的思想都是从函数式编程语言借鉴的,还有从矢量编程语言借来的特性。

当前的软件实现是指定一个“Map”函数,用来把一组键值对映射成一组新的键值对,指定并发的“Reduce”函数,用来保证所有映射的键值对中的每一个都共享相同的键组。

Hadoop MapReduce 的任务过程分为两个阶段:

  • Map 阶段:把大任务分解为若干个小任务来并行处理。这些任务可以并行计算,彼此之间没有依赖关系。
  • Reduce 阶段:对 map 阶段的结果进行全局汇总。

Hadoop 序列化

为什么要序列化?

序列化是我们通过网络通信传输数据时或者把对象持久化到文件,需要把对象序列化成二进制的结构。

观察源码时发现自定义 Mapper 类与自定义 Reducer 类都有泛型类约束,比如自定义 Mapper 有四个泛型参数,但是都不是 Java 基本类型。

为什么 Hadoop 要选择建立自己的序列化格式而不使用 java 自带 serializable?

  • 序列化在分布式程序中非常重要,在 Hadoop 中,集群中多个节点的进程间的通信是通过 RPC(远程过程调用:RemoteProcedureCall)实现;RPC 将消息序列化成二进制流发送到远程节点,远程节点再将接收到的二进制数据反序列化为原始的消息,因此 RPC 往往追求如下特点:

    • 数据更紧凑,能充分利用网络带宽资源
    • 快速:序列化和反序列化的性能开销更低
  • Hadoop 使用的是自己的序列化格式 Writable,它比 java 的序列化 serialization 更紧凑速度更快。一个对象使用 Serializable 序列化后,会携带很多额外信息比如校验信息,Header,继承体系等

Java 基本类型与 Hadoop 常用序列化类型

Java 基本类型 Hadoop Writable 类型
boolean BooleanWritable
byte ByteWritable
int IntWritable
float FloatWritable
long LongWritable
double DoubleWritable
String Text
map MapWritable
array ArrayWritable

基本的序列化类型往往不能满足需求,比如我们常常需要传递一些自定义的 bean 对象。在 Hadoop 中为了实现自定义对象序列化需要实现 Writable 接口。

  1. 实现 Writable 接口
  2. 有无参构造函数
  3. 重写序列化 write 方法和反序列化 readFields 方法。(注意序列化和反序列化的字段顺序必须完全一致)
  4. 如果自定义 Bean 对象需要放在 Mapper 输出 KV 中的 K 里面,那么该对象还需要实现 Comparable 接口,因为 MapReduce 框架中的 Shuffle 过程要求 key 必须能排序

案例实战

需求:下面有一个水果摊老板的一个售卖记录,这三列分别是:水果名称、水果重量、还有总价。我们需要统计每个水果的总重量和重价。

苹果 3 12
李子 4 8
苹果 2 8
桃子 4 20
香蕉 2 4
火龙果 1 4
  1. 配置 Hadoop 环境变量
  2. 导入 maven 依赖
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${hadoop-version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop-version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${hadoop-version}</version>
</dependency>
  1. 编写保存售卖记录的实体类
@Setter
@Getter
public class FruitsRecord implements Writable { private int weight; private double totalPrice; @Override
public void write(DataOutput out) throws IOException {
out.writeInt(weight);
out.writeDouble(totalPrice);
} @Override
public void readFields(DataInput in) throws IOException {
this.weight = in.readInt();
this.totalPrice = in.readDouble();
} @Override
public String toString() {
return "FruitsRecord{" +
"weight=" + weight +
", totalPrice=" + totalPrice +
'}';
}
}
  1. 编写 Mapper 类
import com.mmc.hadoop.bean.FruitsRecord;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class FruitsMapper extends Mapper<LongWritable,Text,Text, FruitsRecord> { @Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, FruitsRecord>.Context context) throws IOException, InterruptedException {
//获取一行的数据
String line = value.toString(); String[] fields = line.split(" "); Text outKey= new Text(fields[0]);
FruitsRecord fruitsRecord=new FruitsRecord();
fruitsRecord.setWeight(Integer.parseInt(fields[1]));
fruitsRecord.setTotalPrice(Double.parseDouble(fields[2])); context.write(outKey,fruitsRecord);
}
}
  1. 编写 Reduce 类
import com.mmc.hadoop.bean.FruitsRecord;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class FruitsReducer extends Reducer<Text, FruitsRecord,Text,FruitsRecord> { @Override
protected void reduce(Text key, Iterable<FruitsRecord> values, Reducer<Text, FruitsRecord, Text, FruitsRecord>.Context context) throws IOException, InterruptedException {
int totalWeight = 0;
double totalPrice =0; for (FruitsRecord fruitsRecord : values){
totalWeight += fruitsRecord.getWeight();
totalPrice+= fruitsRecord.getTotalPrice();
} FruitsRecord fruitsRecord = new FruitsRecord();
fruitsRecord.setWeight(totalWeight);
fruitsRecord.setTotalPrice(totalPrice); context.write(key, fruitsRecord); }
}
  1. 编写 Driver 类
import com.mmc.hadoop.bean.FruitsRecord;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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.output.FileOutputFormat; import java.io.IOException; public class FruitsDriver { public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
// System.setProperty("java.library.path","d://");
Configuration conf = new Configuration();
Job job=Job.getInstance(conf,"FruitsDriver"); //指定本程序的jar包所在的路径
job.setJarByClass(FruitsDriver.class); //指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(FruitsMapper.class);
job.setReducerClass(FruitsReducer.class); //指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FruitsRecord.class); //指定reduce输出数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FruitsRecord.class); //指定job的输入文件目录和输出目录
FileInputFormat.setInputPaths(job,new Path(args[0]));
FileOutputFormat.setOutputPath(job,new Path(args[1])); boolean result = job.waitForCompletion(true);
System.exit( result ? 0: 1); }
}

总结:

Mapper 里面,Mapper 类的四个泛型分别为入参的 KV 和出参的 KV。Reduce 里面的也有4个泛型,分别为入参的KV和出参的KV。Reduce入参的 KV 与 Mapper 里面出参的 KV 类型是对应的。只不过 Reduce 的入参的 Value 类型是集合类型的。

时序图如下:

运行任务

本地模式

直接在 IDEA 中运行驱动类即可。因为程序里输入文件路径和输出文件路径是取的 main 函数里的 args。所以运行的时候需要指定参数。

遇到的问题

问题 1:

问题 2:创建目录错误

org.apache.hadoop.io.nativeio.NativeIO$Windows.createDirectoryWithMode0(Ljava/lang/String

解决方案:

两个问题都是 windows 的 hadoop/bin 目录下缺少文件导致的。文件下载路径:https://github.com/cdarlint/winutils

  1. 找到对应版本的 hadoop.dll 和 winutils.exe 下载下来放到 hadoop/bin 目录下。
  2. C: windows\System32 放入 hadoop.dll 文件
  3. 重启电脑

输出目录:

打开结果文件 part-r-00000:

李子	FruitsRecord{weight=4, totalPrice=8.0}
桃子 FruitsRecord{weight=4, totalPrice=20.0}
火龙果 FruitsRecord{weight=1, totalPrice=4.0}
苹果 FruitsRecord{weight=5, totalPrice=20.0}
香蕉 FruitsRecord{weight=2, totalPrice=4.0}

Yarn 集群模式

  1. 把程序打包成 jar 包,上传到 linux
  2. 将测试的 txt 上传到 HDFS 上面
  3. 启动 Hadoop 集群
  4. 使用 Hadoop 命令提交任务运行
hadoop jar wc.jar com.mmc.hadoop.FruitsDriver
/user/input /user/output

MapReduce入门实战的更多相关文章

  1. Spark入门实战系列--10.分布式内存文件系统Tachyon介绍及安装部署

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Tachyon介绍 1.1 Tachyon简介 随着实时计算的需求日益增多,分布式内存计算 ...

  2. Spark入门实战系列--1.Spark及其生态圈简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .简介 1.1 Spark简介 年6月进入Apache成为孵化项目,8个月后成为Apache ...

  3. Spark入门实战系列--2.Spark编译与部署(中)--Hadoop编译安装

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .编译Hadooop 1.1 搭建环境 1.1.1 安装并设置maven 1. 下载mave ...

  4. Spark入门实战系列--2.Spark编译与部署(下)--Spark编译安装

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .编译Spark .时间不一样,SBT是白天编译,Maven是深夜进行的,获取依赖包速度不同 ...

  5. Spark入门实战系列--3.Spark编程模型(上)--编程模型及SparkShell实战

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Spark编程模型 1.1 术语定义 l应用程序(Application): 基于Spar ...

  6. Spark入门实战系列--4.Spark运行架构

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 1. Spark运行架构 1.1 术语定义 lApplication:Spark Appli ...

  7. Spark入门实战系列--5.Hive(上)--Hive介绍及部署

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Hive介绍 1.1 Hive介绍 月开源的一个数据仓库框架,提供了类似于SQL语法的HQ ...

  8. Spark入门实战系列--6.SparkSQL(上)--SparkSQL简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .SparkSQL的发展历程 1.1 Hive and Shark SparkSQL的前身是 ...

  9. Spark入门实战系列--8.Spark MLlib(上)--机器学习及SparkMLlib简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .机器学习概念 1.1 机器学习的定义 在维基百科上对机器学习提出以下几种定义: l“机器学 ...

随机推荐

  1. 关于git flow的一点思考

    本文首发自我的公众号:成都有娃儿,这里把三篇文章合一,方便阅读. 现在相当多的公司或者团队都在使用git来做版本控制,结合我这些年的工作经历,我总结了一些个人认为不错的使用规范和习惯. 脱离背景来讲规 ...

  2. 用STM32玩SR04(测距、串口显示、OLED显示)

    目录 用STM32玩SR04(测距.串口显示.OLED显示) 超声波模块使用 SR04初始化 SR04使用串口打印数据 SR04使用OLED来传输数据,并显示在OLED上 用STM32玩SR04(测距 ...

  3. QT 基于QScrollArea的界面嵌套移动

    在实际的应用场景中,经常会出现软件界面战场图大于实际窗体大小,利用QScrollArea可以为widget窗体添加滚动条,可以实现小窗体利用滚动条显示大界面需求.实现如下: QT创建一个qWidget ...

  4. 物联网lora模块应用案例和LoRawan网关通信技术

    什么是LoRa LoRa(Long Range) 无线通信技术是 Semtech 在2012年开发出来的一款适合物联网使用的射频IC.其设计理念为低功耗.长距离.低成本.网路简单.易于扩展的无线数传技 ...

  5. 腾讯云数据库TDSQL-大咖论道 | 基础软件的过去、现在、未来

    近十年来,中国基础软件发展势头迅猛,市场前景看高,越来越多的企业也正在进行基础软件升级.那中国基础软件行业目前在国际市场上有什么优势,面临哪些困境,以及未来基础软件行业会如何发展呢?腾讯云数据库邀请沙 ...

  6. JS:this关键字1

    this 代表了当前的对象,哪个对象调用了this所在的函数,this就代表了哪个对象: 例1: function fn(){ var a = 1; console.log(this) } fn() ...

  7. Apache ShardingSphere 5.1.2 发布|全新驱动 API + 云原生部署,打造高性能数据网关

    在 Apache ShardingSphere 5.1.1 发布后,ShardingSphere 合并了来自全球的团队或个人的累计 1028 个 PR,为大家带来 5.1.2 新版本.该版本在功能.性 ...

  8. 关于使用 koa路由与mysql模块, ctx.body获取不到值的问题

    var Koa = require('koa');var Router = require('koa-router' );var bodyParser = require('koa-bodyparse ...

  9. JavaScript做简单的购物车效果(增、删、改、查、克隆)

    比如有时候遇到下面这种情况,点击加入购物车,然后在上方的购物车中动态的添加商品以及商品的信息,我们就可以通过JavaScript实现简单的这些操作. 首先我们需要在html文档中,通过css对页面的布 ...

  10. UiPath培训教程

    匠厂出品,必属精品   Uipath中文社区qq交流群:465630324 uipath中文交流社区:https://uipathbbs.comRPA之家qq群:465620839 第一课--UiPa ...