基础
本课程向读者介绍了MapReduce编程范式。
Map 和 Reduce
MapReduce 是 “map” 和 “reduce” 的组合,准确描述了其包含的两个阶段。MapReduce 是 Google 提出的一种计算模型的实现。在此模型中,数据并行计算在由不可靠机器组成的集群上执行,由特定系统完成。这些系统自动提供基于数据本地性的调度、容错能力以及负载均衡功能。简单来说,可以将 MapReduce 理解为一种“分而治之”的策略:一个庞大的数据集被分配到多个工作节点上进行处理;当处理完成后,各节点的结果被汇总,形成最终的解决方案。MapReduce 作业各个阶段的数据流动如下所示。
MapReduce 是一种编程模型,用于在由通用硬件组成的集群上,通过分布式算法处理大规模数据集。
尽管具有诸多优势,MapReduce 本质上是一个批处理系统,不适用于交互式分析。你无法运行一个查询并快速获得结果。查询通常需要几分钟甚至更长时间,因此更适合离线使用,即没有用户在等待结果的场景下。对于交互式需求,其他大数据工具如 Spark 和 Impala 可能更为合适。该模型包含两个阶段:
- Map 阶段:用户定义一个 map 函数,用于处理键值对,并生成一组中间键值对。
- Reduce 阶段:Reduce 阶段将所有与相同中间键关联的中间值合并。
我们稍后会通过一个例子来演示这两个步骤。从根本上说,MapReduce 是一种解决大数据挑战的“分而治之”方法。许多现实世界的问题都可以用 map 和 reduce 的范式来表达。
特性
MapReduce 编程模型具有以下特点:
- 分布式:MapReduce 是一个分布式框架,由通用硬件组成的集群构成,用于运行 map 或 reduce 任务。
- 并行:map 和 reduce 任务始终并行执行。
- 容错:如果某个任务失败,系统会在另一台节点上重新调度该任务。
- 可扩展:系统可任意扩展。随着问题规模增大,可以通过增加更多机器,在合理时间内解决问题;框架支持横向扩展而非纵向扩展。
输入与输出
该框架仅处理键值对。map 和 reduce 阶段的输入和输出均以键值对形式存在。但对输入和输出有如下限制:
- 可序列化:框架要求键和值都必须是可序列化的,并且必须实现
Writable接口。 - 可比较:框架在将 map 阶段的输出传递给 reduce 阶段之前会进行排序。排序要求键之间可以相互比较,因此键必须实现
WritableComparable接口。
Map 阶段
Map 是独立的任务,负责将输入记录转换为中间记录。这些中间记录的类型不必与输入记录相同。一个输入的键值对可能映射为零个或多个输出键值对。
Reduce 阶段
由 map 阶段输出的中间键值对集合,会被 reducer 合并为更少的键值对。
示例
假设你计划在某个社区开设一家新业务,为此你需要估算该社区居民的消费能力。你决定通过统计经过该区域的车辆数量及其品牌,作为衡量潜在客流消费能力的代理指标。如果看到大量高档汽车经过,就可以合理推测会有较多顾客。一种收集此类信息的方法是在不同街道安排人工观察员来记录数据。事实上,不久前石油公司也曾采用类似方法评估新建加油站的可行性。他们会连续数天手动统计经过的车辆数量,以判断某个地点是否适合开设加油站。
现在设想你收到一个包含全部数据的文件,格式如下:
1Toyota Toyota Mercedes-Benz 2BMW Tesla Porsche 3Porsche Tesla GM Volvo ford
每行代表一天的数据,列出的品牌之间用空格分隔。第一行表示第一天,第一个看到的车是丰田,第二个也是丰田,第三个是梅赛德斯-奔驰。如果这个文件包含数 GB 甚至 PB 级别的数据,人工统计每种车型的数量将完全不切实际。同样,传统计算方法也可能无法处理或耗时过长。
这个问题的解决方案可以通过 MapReduce 范式来实现。MapReduce 在解决矩阵乘法、聚合操作以及 SQL 中的 group by 查询方面也非常有效。能够用 MapReduce 解决的问题必须具备可并行化的特性,即各个部分可以独立求解,产生中间结果,再合并得到最终答案。