2 关于 MapReduce

  • 一种可用于数据处理的编程模型。
    • 模型简单,但要想写出有用的程序却不太容易。
  • Hadoop可运行各种语言版本的Mapreduce程序。
  • 本章看到同一个程序的Java、Ruby和 Python语言版本。
  • 最重要的是Mapreduce程序本质上并行运行,因此可将大规模的数据分析任务分发给任何一个拥有足够多机器的数据中心。
  • Mapreduce的优势在于处理大规模数据集,所以这里先来看一个数据集。

2.1气象数据集

  • 挖掘气象数据的程序。
  • 全球各地的气象传感器每隔一小时收集气象数据和收集大量日志数据,
  • 希望处理所有这些数据,
    • 这些数据半结构化的
    • 且按记录方式存储,
    • 非常适合用Mapreduce分析

数据格式

  • 数据来自NCDC
  • 按行并以ASCII格式存储,每行是一条记录
  • 该存储格式支持丰富的气象要素,
    • 许多要素可选择性列入收集范围
    • 数据所需的存储长度是可变
  • 重点讨论基本要素(如气温)
    • 长度都固定

  • 范例2-1显示一行采样数据
  • 这一行数据被分成很多行以突出每个字段,
    • 实际中,
    • 这些字段合并成一行,没有分隔符。

在这里插入图片描述

  • 文件按日期和气象站组织。
  • 1901年到2001年,每一年都有一个目录,每一个目录中包含各个气象站该年气象数据的打包文件及其说明文件。
  • 1999年对应文件夹下面就包含下面的记录

在这里插入图片描述

  • 气象台成千上万,整个数据集由大量小文件组成
  • 处理少量大型文件更容易、更有效,
    • 这些数据需要经过预处理,
    • 将每年的数据文件拼接成一个单独的文件。
  • 做法请参见附录C。

2.2使用Unix工具来分析数据

  • 每年全球气温的最高记录?
  • 先不用Hadoop
    • 只有提供了性能基准和结果检査工具,
    • 才能和Hadoop进行有效对比

  • 传统处理按行存储数据的工具是awk。
  • 范例2-2是计算每年的最高气温。

在这里插入图片描述

  • 脚本循环遍历按年压缩文件
    • 先显示年份,然后用awk处理每文件
  • awk从数据中提取两字段:气温和质量代码
    • 气温值加0后转换为整数。
    • 接着测试气温值是否有效(999替代NCDC数据集中的缺失的值),
      • 通过质量代码检测数值是否有错
  • 如果正确,该值将与目前读取到的最大气温值比较
  • 处理完文件中所有的行后,
    • 再执行END块中的代码并在屏幕上输出最大气温

在这里插入图片描述

  • 亚马逊的EC2 High-CPU Extra Large Instance运行,
    • 42分钟就可处理完一个世纪的气象数据,
    • 找出最高气温

  • 为加快处理,需并行处理程序
  • 理论上,很简单:可用计算机上所有可用的硬件线程来处理,
    • 每个线程负责处理不同年份数据
  • 将任务划分成大小相同的作业通常并不是一件容易的事情。
    • 不同年份数据文件的大小差异很大,有一部分线程会比其他线程更早结束。
    • 即使可再为它们分配下一个作业,但总的运行时间仍然取决于处理
      最长文件所需要的时间
  • 将输入数据分成固定大小的块,
    • 然后每块分到各个进程去执行,
    • 这样一来,即使有一些进程可以处理更多数据,
    • 我们也可以为它们分配更多的数据。

  • 合并各个独立进程的运行结果,还需额外处理。
  • 每年的结果独立于其他年份,
    • 可能需把所有结果拼接起来,然后再按年份排序
  • 如果用固定块大小,则需一种精巧方法合并结果。
    • 某年的数据通常被分割成几个块,每个块独立处理。
  • 最终获得每个块的最高气温,
    • 最后一步找出最大值作为该年的最高气温,
    • 其他年份的数据都像这样处理。

  • 受限于单台计算机的能力。
  • 即便开足马力,用上所有处理器,至少也20分钟,系统无法更快。
  • 某些数据集的增长可能会超出单台计算机的处理能力
    • 一旦开始用多台计算机,整个大环境中的其他因素就会互相影响,
    • 协调性和可靠性两方面。
  • 哪个进程负责运行整个作业?
  • 如何处理失败的进程?

  • 并行处理也是可行的,但实际麻烦。
  • 可借助于 Hadoop类似框架来解决这些问题。

2.3使用 Hadoop来分析数据

  • 为充分利用Hadoop提供的并行处理优势,
    • 我们需将查询表示成Mapreduce作业。
  • 完成某种本地端的小规模测试之后,就可以把作业部署到在集群上运行

2.3.1 map和 reduce

  • Mapreduce过程两阶段:
    • 毎阶段都以键值对作为输入和输出,类型由程序员选择
  • 需写两函数:map函数和 reduce函数

  • map阶段的输入是NCDC原始数据。
  • 文本格式为输入格式,将数据集的每行作为文本输入。
  • 键是某一行起始位置相对于文件起始位置的偏移量
    • 不需这信息,忽略

  • 只对年份和气温属性感兴趣,只需取出这两字段
  • map函数只是一个数据准备阶段
    • 通过这种方式来准备数据,使reduce能继续对它处理:
  • map函数还是一个比较适合去除已损记录的地方:
  • `此处,筛掉缺失的、可疑的或错误的气温数据。

  • 以下输入数据的示例(考虑篇幅,去除一些未使用的列,省略号表示)

在这里插入图片描述

在这里插入图片描述

  • 键是文件中的行偏移量,map函数不要这信息,将其忽略。
  • map的功能提取年份和气温信息
    • 并将它们作为输出(气温值已用整数表示)

在这里插入图片描述

  • map函数的输出经Mapreduce框架处理后,发送到reduce函数。
  • 这个处理过程基于键来对键-值对排序和分组。
  • 因此,在这一示例中, reduce函数看到的是如下输入

在这里插入图片描述

  • 年份后紧跟着一系列气温数据。
  • reduce函数遍历整个列表并从中找出最大

在这里插入图片描述

  • 数据流如图2-1。
  • 图的底部是Unix管线,模拟整个 Mapreduce的流程,
    • 部分内容在讨论Hadoop Streaming时再次涉及。

2.3.2 Java Mapreduce

  • 要三样东西:map函数、reduce函数和一些用来运行作业的代码。
  • map函数由Mapper类表示,
    • 声明一个抽象的map()方法。
    • 范例2-3显示了我们的map函数实现。

在这里插入图片描述

  • Mapper类是一个泛型类型,
    • 四形参类型
    • 分别指定map函数的输入键、输入值、输出键和输出值的类型。
    • 输入键是一个长整数偏移量,
    • 输入值是一行文本,
    • 输出键是年份,输出值是气温(整数)
  • Hadoop提供一套可优化网络序列化传输的基本类型,而不直接使用Java内嵌的类型。
    • org.apache. hadoop.io包
    • Longwritable类型(Java的Long)、Text类型(String)
    • Intwritable类型(Integer)。

  • map()的输入是一个键和一个值。
  • 首先将包含有一行输入的Text值转换成Java的 string类型,之后用 substring()方法提取我们感兴趣的列。

  • map()方法还提供Context实例用于输出内容的写入
  • 这种情况将年份数据按Text对象读/写(因为我们把年份当作键),将气温值封装在Intwritable
  • 只有气温数据不缺
    • 对应质量代码为正确的气温读数时,
    • 这些数据才会被写入输出记录中。

  • 类似方法用Reducer来定义 reduce函数,如范例2-4
发布了558 篇原创文章 · 获赞 295 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zhoutianzi12/article/details/105395357
今日推荐