1. Hadoop简介
1.1 背景介绍
Hadoop是Apache旗下的开源的分布式计算平台,它可以运行在计算机集群之上,提供可靠的、可扩展的分布式计算功能。
Hadoop与三遍论文密不可分:
① 2003年,谷歌发布的分布式文件系统GFS的论文,可以用于解决海量数据存储的问题。
② 2004年,谷歌发布了MapReduce的论文,可以用于解决海量数据计算的问题。
③ 2006年,谷歌发布了BigTable的论文,它是以GFS为底层数据存储的分布式存储系统。
Hadoop中的HDFS是GFS的开源实现;
Hadoop中的MapReduce是谷歌MapReduce的开源实现;
Hadoop中的HBase是谷歌BigTable的开源实现。
1.2 Hadoop核心组件
Hadoop由四个主要模块组成:
Hadoop Common: 一组工具和库,可补充其他模块并确保与用户计算机系统的兼容性;
Hadoop Distributed File System (HDFS):提供可对应用数据进行高吞吐量访问的分布式文件系统。;
Hadoop YARN(Yet Another Resource Negotiator):作业调度和集群资源管理框架;
Hadoop MapReduce:基于YARN的大数据集并行处理系统,从数据库读取,转换和分析数据。
Hadoop生态系统
在大数据处理当中,最核心要解决的其实就是两个问题,大数据存储和大数据计算。在Hadoop生态当中,解决大数据存储,主要依靠就是HDFS,再配合数据库去完成。而MapReduce为海量的数据提供了计算。
1.2.1 HDFS
HDFS是什么
HDFS即Hadoop distributed file system(hadoop分布式文件系统),在Hadoop当中负责分布式存储阶段的任务,它是一个分布式的文件系统,也可以用来存放单个机器的数据,只是大部分用来存储分布式数据。HDFS跟window下的NTFS一样可以通过目录树来查找数据。
HDFS有什么用
整个Hadoop框架,本质上来说都是基于分布式实现的,随着数据规模的越来越大,一台机器无法存储所有的数据,所以需要多台机器来存储。而多台机器存储又不方便管理,所以需要一个分布式的系统来管理分布在不同机器中的数据。
事实上,HDFS的出现,就是为了解决分布式框架下,数据存储管理的问题。而HDFS只是分布式文件系统中的一种,依托于Hadoop生态,去承担大数据分布式存储的管理任务。
HDFS的概念与架构
HDFS是典型的主/从架构。HDFS集群由一个NameNode组成,NameNode是一个主服务器,它管理文件系统名称空间并控制客户机对文件的访问。此外,还有许多datanode,通常是集群中的每个节点一个datanode,它们管理附加到它们所运行的节点上的存储。
Namenode:
即master,有以下功能
*管理文件系统命名空间;
*控制client对数据的读取和写入请求;
*管理数据块到datanode的映射关系;
*管理副本策略。
Datanode:
即slave,主要是存储文件块数据,接受来自namenode的指令,并执行指令对数据块的创建,删除,复制等操作。
Client:
即客户端,有以下功能:
*对文件的切分,HDFS上传数据时,client将文件切分成多个block再进行上传;
*与namenode交互,获取文件的索引信息;
*与datanode交互,对数据的读取和写入;
*在客户端中提供相关HDFS的命令,比如对HDFS的管理,格式化namenode,对HDFS对数据操作,比如上传文件到HDFS等。
Secondary namenode:
并非namenode的热备,当namenode挂掉的时候,并不能立马替换namenode并提供服务,只是在定时的对namenode进行备份,存在一定的时间误差,secondary会备份namenode的Fsimage和Edits,在紧急情况下,可以适用secondarynamenode来恢复部分的namenode。
关于大数据学习,Hadoop HDFS存储入门,以上就为大家做了简单的介绍了。在Hadoop大数据框架当中,HDFS作为分布式文件系统,始终是重要的核心组件,学习当中也自然需要深入理解掌握。
参考:
https://www.jianshu.com/p/fe77da35b653
1.2.2 YARN
Yarn 的全称是 Yet Another Resource Negotiator,意思是“另一种资源调度器”
Container
容器(Container)这个东西是 Yarn 对资源做的一层抽象。就像我们平时开发过程中,经常需要对底层一些东西进行封装,只提供给上层一个调用接口一样,Yarn 对资源的管理也是用到了这种思想。
如上所示,Yarn 将CPU核数,内存这些计算资源都封装成为一个个的容器(Container)。需要注意两点:
- 容器由 NodeManager 启动和管理,并被它所监控。
- 容器被 ResourceManager 进行调度。
ResourceManager(RM)
从名字上我们就能知道这个组件是负责资源管理的,整个系统有且只有一个 RM ,来负责资源的调度。它也包含了两个主要的组件:定时调用器(Scheduler)以及应用管理器(ApplicationManager)。
- 定时调度器(Scheduler):从本质上来说,定时调度器就是一种策略,或者说一种算法。当 Client 提交一个任务的时候,它会根据所需要的资源以及当前集群的资源状况进行分配。注意,它只负责向应用程序分配资源,并不做监控以及应用程序的状态跟踪。
- 应用管理器(ApplicationManager):应用管理器就是负责管理 Client 用户提交的应用。定时调度器(Scheduler)不对用户提交的程序监控,监控应用的工作正是由应用管理器(ApplicationManager)完成的。
ApplicationMaster
每当 Client 提交一个 Application 时候,就会新建一个 ApplicationMaster 。由这个 ApplicationMaster 去与 ResourceManager 申请容器资源,获得资源后会将要运行的程序发送到容器上启动,然后进行分布式计算。
为什么是把运行程序发送到容器上去运行?如果以传统的思路来看,是程序运行着不动,然后数据进进出出不停流转。但当数据量大的时候就没法这么玩了,因为海量数据移动成本太大,时间太长。大数据分布式计算就是这种思想,既然大数据难以移动,那我就把容易移动的应用程序发布到各个节点进行计算呗,这就是大数据分布式计算的思路。
NodeManager
NodeManager 是 ResourceManager 在每台机器的上代理,负责容器的管理,并监控他们的资源使用情况(cpu,内存,磁盘及网络等),以及向 ResourceManager/Scheduler 提供这些资源使用报告。
提交一个 Application 到 Yarn 的流程
这张图简单地标明了提交一个程序所经历的流程,接下来我们来具体说说每一步的过程。
- Client 向 Yarn 提交 Application,这里我们假设是一个 MapReduce 作业。
- ResourceManager 向 NodeManager 通信,为该 Application 分配第一个容器。并在这个容器中运行这个应用程序对应的 ApplicationMaster。
- ApplicationMaster 启动以后,对 作业(也就是 Application) 进行拆分,拆分 task 出来,这些 task 可以运行在一个或多个容器中。然后向 ResourceManager 申请要运行程序的容器,并定时向 ResourceManager 发送心跳。
- 申请到容器后,ApplicationMaster 会去和容器对应的 NodeManager 通信,而后将作业分发到对应的 NodeManager 中的容器去运行,这里会将拆分后的 MapReduce 进行分发,对应容器中运行的可能是 Map 任务,也可能是 Reduce 任务。
- 容器中运行的任务会向 ApplicationMaster 发送心跳,汇报自身情况。当程序运行完成后, ApplicationMaster 再向 ResourceManager 注销并释放容器资源。
参考:https://zhuanlan.zhihu.com/p/54192454
1.2.3 MapReduce
MapReduce是Hadoop的核心框架之一,主要负责分布式并行计算。MapReduce 既是计算框架,也是编程模型,主要基于Java语言来编程,这也是为什么Hadoop学习要求要有一定的Java基础。当然,在这几年的发展当中,MapReduce的计算性能受到诟病,取而代之受到重用的是Spark。
MapReduce运行过程,通常涉及到input、split、map、shuffle、reduce、output几个阶段,其中shuffle过程包括sort、copy、combine操作,reduce之前有时涉及二次排序。
MapReduce编程,主要有三种方式:
1、Hadoop streaming执行mapreduce
2、Hive执行mapreduce
3、Java MR编程
①Hadoop streaming执行MapReduce
优点:
可以用大多数语言开发;
代码量少,开发速度快;
方便本地调试。
不足:
只能通过参数控制MR框架,控制性较弱,比如定制partitioner、combiner;
支持的数据类型和数据结构有限,不适合做复杂处理,处理字符型较多;
②Hive执行MapReduce
将类SQL转换成MapReduce,定位于数据仓库。
优点:
开发速度快,易调试,易理解;
易于构建数据仓库模型;
内置函数功能齐全,比如rownumber等窗口函数;
可扩展性好,比如自定义存储格式、自定义函数UDF;
多接口,比如JDBC、Thrift、Rest等。
缺点:
不能用于复杂计算,比如涉及时序处理的数据;
可控制性较弱,比如partition、关联等操作。
③Java MR编程
用Java编写MR,可以说是最“原始”的一种方式,Java面向对象编程,设计模式成熟,通用性好,并且Java方面第三方类库非常丰富。
优点:
定制性强,比如定制partitioner、定制combiner等;
数据类型和数据结构丰富,队列、堆栈、自定义类等使用方便;
控制性非常高,包括MR运行过程的一些控制,Map端join等;
可以方便使用Hadoop组件类库中的类或工具,比如HDFS文件操作类等。
缺点:
相比Hive、Hadoop streaming或Pyspark,开发代码量较大,对开发环境要求高且不易调试;
通常每个操作都要写一个MR类;
不如Spark执行效率高。
参考:https://www.jianshu.com/p/3c9aa4214dd3
1.3 Hadoop的特点
① 跨平台性:
hadoop是基于java语言开发的,有很好的跨平台性,可以运行在Linux平台上;
② 高可靠性:
hadoop中的HDFS是分布式文件系统,可以将海量数据分布冗余存储在不同的机器节点上,即使是某个机器副本上发生故障,其他的机器副本也能正常运行;
③ 高容错性:
HDFS把把文件分布存储在很多不同的机器节点上,能实现自动保存多个副本,因此某个节点上的任务失败后也能实现自动重新分配;
④ 高效性:
hadoop的核心组件HDFS和MapReduce,一个负责分布式存储一个负责分布式处理,能够处理PB级别的数据;
⑤ 低成本与高扩展:
hadoop在廉价的计算机集群上就可以运行,因此成本比较低,并且可以扩展到几千个计算机节点上,完成海量数据的存储和计算。
参考:
https://zhuanlan.zhihu.com/p/369486877
1.4 应用实例
-
Adobe
- We use Apache Hadoop and Apache HBase in several areas from social services to structured data storage and processing for internal use.
- We currently have about 30 nodes running HDFS, Hadoop and HBase in clusters ranging from 5 to 14 nodes on both production and development. We plan a deployment on an 80 nodes cluster.
- We constantly write data to Apache HBase and run MapReduce jobs to process then store it back to Apache HBase or external systems.
- Our production cluster has been running since Oct 2008.
-
Alibaba
- A 15-node cluster dedicated to processing sorts of business data dumped out of database and joining them together. These data will then be fed into iSearch, our vertical search engine.
- Each node has 8 cores, 16G RAM and 1.4T storage.
- Facebook
- We use Apache Hadoop to store copies of internal log and dimension data sources and use it as a source for reporting/analytics and machine learning.
- Currently we have 2 major clusters:
- A 1100-machine cluster with 8800 cores and about 12 PB raw storage.
- A 300-machine cluster with 2400 cores and about 3 PB raw storage.
- Each (commodity) node has 8 cores and 12 TB of storage.
- We are heavy users of both streaming as well as the Java APIs. We have built a higher level data warehousing framework using these features called Hive (see the http://hadoop.apache.org/hive/). We have also developed a FUSE implementation over HDFS.
参考:https://cwiki.apache.org/confluence/display/hadoop2/PoweredBy
2. Hadoop安装
2.1 安装前的准备
2.1.1 支持的平台
- GNU/Linux是产品开发和运行的平台。 Hadoop已在有2000个节点的GNU/Linux主机组成的集群系统上得到验证。
本文将以Ubuntu 18.04作为安装平台 - Windows平台同样受官方支持。可参考官方文档或者自行百度谷歌https://cwiki.apache.org/confluence/display/HADOOP2/Hadoop2OnWindows
2.1.2 需要提前安装的软件
Java
官方现在推荐OpenJDK,其他版本(比如Oracle)也可以
Hadoop 3.3.x支持Java 8 和 Java 11,推荐Java 8
Hadoop 3.0.x 到 3.2.x n只支持 Java 8
Hadoop from 2.7.x 到 2.10.x 同时支持 Java 7 and 8
本文安装Hadoop 3.2.2, OpenJDK版本为系统自带的1.8.0
ssh
必须安装并且保证 sshd一直运行,以便用Hadoop 脚本管理远端Hadoop守护进程
安装ssh
sudo apt-get install ssh
2.1.3 下载Hadoop
考虑到网速以及以后适配Spark的版本问题,我们选择比较新的Hadoop 3.2.2稳定发行版。香港可以直接从官网下载https://hadoop.apache.org/releases.html
内地可以使用镜像网站,比如清华镜像
https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.2.2/
2.2 安装过程(单机版)
参考
https://www.jianshu.com/p/cdae5bab030f
https://blog.csdn.net/weixin_42001089/article/details/81865101
https://blog.csdn.net/qq_44830040/article/details/104873759
https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html
集群配置
https://blog.csdn.net/qq_39785575/article/details/106300628
2.3 环境变量设置
2.4 Hadoop 启动
格式化namenode
hadoop namenode -format
启动hdfs
start-all.sh
查看相应进程
jps
浏览器访问
localhost:9870
3. Hadoop 应用
3.1 上传文件到HDFS
3.1.1 Linux 命令行
(1)格式画NameNode
hdfs namenode -format
(2) 启动hdfs
start-all.sh
(3)查看hdfs状态
hdfs dfsadmin -report
(4)上传文件到hdfs
hdfs dfs -put 要上传的文件路径 目标路径
#举例
hdfs dfs -put test.txt /
(5)查看hdfs路径下的文件
hdfs dfs -ls /
(6)读取hdfs文件内容
hdfs dfs -cat /test.txt
(7)删除hdfs文件
hdfs dfs -rm /test.txt
3.1.2 Java
略
3.2 MapReduce
3.2.1 MapReduce是什么
(1) MapReduce是一种分布式计算框架 ,以一种可靠的,具有容错能力的方式并行地处理上TB级别的海量数据集。主要用于搜索领域,解决海量数据的计算问题。
(2) MapReduce有两个阶段组成:Map和Reduce,用户只需实现map()和reduce()两个函数,即可实现分布式计算。
3.2.2 MapReduce做什么
(1) MapReduce框架由Map和Reduce组成。
(2) Map()负责把一个大的block块进行切片并计算。
(3) Reduce() 负责把Map()切片的数据进行汇总、计算。
3.2.3 MapReduce怎么做
(1) 第一步对输入的数据进行切片,每个切片分配一个map()任务,map()对其中的数据进行计算,对每个数据用键值对的形式记录,然后输出到环形缓冲区(图中sort的位置)。
(2) map()中输出的数据在环形缓冲区内进行快排,每个环形缓冲区默认大小100M,当数据达到80M时(默认),把数据输出到磁盘上。形成很多个内部有序整体无序的小文件。
(3) 框架把磁盘中的小文件传到Reduce()中来,然后进行归并排序,最终输出。
3.2.4 要点是什么
MapReduce是六大过程,简单来说:Input, Split, Map, Shuffle, Reduce, Finalize
(1) MapReduce将输入的数据进行逻辑切片,一片对应一个Map任务
(2) Map以并行的方式处理切片
(3) 框架对Map输出进行排序,然后发给Reduce
(4) MapReduce的输入输出数据处于同一个文件系统(HDFS)
(5) 框架负责任务调度、任务监控、失败任务的重新执行
(6) 框架会对键和值进行序列化,因此键和值需要实现writable接口,框架会对键排序,因此必须实现writableComparable接口。
3.1.5 举个例子
如何统计1TB或1PB文件里的单词数呢
(1) Input: 我们输入很多文档,文档的每一行有很多不同的单词
(2) Split: 找不同的worker分配不同的任务,就是Split过程,那怎么切分呢?每一行文档分给一个worker
(3) Map: 就切分成单词和它出现的次数,写成键值对,每次出现的次数是1,就写1。
(4) Shuffle就是把不同的单词继续放到同样的盒子里面,Bear放一起,Car放一起,这可以由Shuffle写的时候算法来决定。当然现在很多智能都不用做了,有时候还需要随机采样的方式来实现。
(5) Reduce,就是把相同的数据放一起,比如Car有3个就写3,River是2个就写2,最后再放到一起,这样便于提供服务,得到最终结果。
大家可以看到最后箭头指过来是乱序的,也就是说这个执行过程实际上是高度并行的,也不用等待每个都完成,所以说这是一个很好的优化过程。
Hadoop Streaming是一种运行作业的实用工具,它允许用户创建和运行任何可执行程序 (例如:Java, Python, Shell工具)来做为mapper和reducer。
代码形式:
Map输入每一行的ID是key,value是这一行的单词。有这个结果以后就可以统计每个单词出现的次数。Reduce输入的还是各个单词,但后面跟的是一个串,是在里面出现的次数,1,1,1,我们把1加到一起就是sum的过程,这就是MapReduce的整个过程。输出我们的关键词和它的出现次数
3.1.6 再举个例子
参考:
https://zhuanlan.zhihu.com/p/55884610
https://www.cnblogs.com/duanzi6/p/11348960.html
将天气数据每年整合成一个文件,存入hdfs
hdfs dfs -mkdir /ncdc
hdfs dfs -put ~/ncdc/raw/ /ncdc
hdfs 查看命令
hdfs dfs -ls -R
以NCDC原始数据求每个年份最高气温为例:
首先原始数据如下(去除了一些列用省略号表示),这些数据就是map函数的输入:
0067011990999991950051507004...9999999N9+00001+99999999999999...
0043011990999991950051512004...9999999N9+00221+99999999999999...
0043011990999991950051518004...9999999N9-00111+99999999999999...
0043012650999991949032412004...0500001N9+01111+99999999999999...
0043012650999991949032418004...0500001N9+00781+99999999999999...
这些行以键值对的方式作为map函数的输入:
(0,0067011990999991950051507004...9999999N9+00001+99999999999999...)
(106,0043011990999991950051512004...9999999N9+00221+99999999999999...)
(212,0043011990999991950051518004...9999999N9-00111+99999999999999...)
(318,0043012650999991949032412004...0500001N9+01111+99999999999999...)
(424,0043012650999991949032418004...0500001N9+00781+99999999999999...)
其中key是文件中的行偏移量,map函数会提取输入中的年份和气温信息(粗体),并作为输出:
(1950,0)
(1950,22)
(1950,-11)
(1949,111)
(1949,78)
map函数的输出会经过MapReduce计算框架基于键的排序和分组后发送到reduce函数作为输入:
(1949,[111,78])
(1950,[0,22,-11])
reduce遍历值列表找到最大温度后返回:
(1949,111)
(1950,22)
整个MapReduce计算流程如下:
从本地模式到分布式集群计算
处理少量输入数据并不能体现MapReduce计算框架的优势,当有大量输入的数据流时,我们需要分布式文件系统(HDFS)和Hadoop资源管理系统(YARN)实现集群分布式计算。
一、术语
先了解一下关于数据流的一些术语
Job:MapReduce作业,是客户端需要执行的一个工作单元:包括输入数据、MapReduce程序和配置信息
Task:Hadoop会将作业job分成若干个任务(task)执行,其中包括两类任务:map任务和Reduce任务
Input split:输入分片,Hadoop会将MapReduce的输入数据划分成等长的小数据块,称为“分片”,Hadoop为每个分片构建一个map任务,并由该任务运行用户自定义的map函数从而处理分片中的每条记录。
二、分片
1、分片的意义
处理单个分片的时间小于处理整个输入数据花费的时间,因此并行处理每个分片且每个分片数据比较小的话,则整个处理过程会获得更好的负载平衡(因为一台较快的计算机能够处理的数据分片比一台较慢的计算机更多,且成一定比例)。
2、分片的大小
尽管随着分片切分得更细,负载平衡的质量也会更高。但是分片切分得太小的时候,管理分片的总时间和构建map任务的总时间将决定整个作业的执行时间。
对于大多数作业来说,一个合理的分片大小趋于HDFS一个块的大小,默认是128MB。
三、数据本地化优化(map任务)
Hadoop在存储有输入数据(HDFS中的数据)的节点上运行map任务,可以获得最佳性能(因为无需使用宝贵的集群带宽资源),这就是“数据本地化优化”(data locality optimization)。
1、本地数据、本地机架与跨机架map任务
有时候存储该分片的HDFS数据块复本的所有节点可能正在运行其他map任务,此时作业调度需要从某一数据块所在的机架中一个节点寻找一个空闲的map槽(slot)来运行该map任务分片。特别偶然的情况下(几乎不会发生)会使用其他机架中的节点运行该map任务,这将导致机架与机架之间的网络传输。下图显示了这三种可能性。
2、数据本地化原则决定了最佳分片大小
数据本地化的原则解释了为什么最佳分片大小应该与HDFS块大小相同:因为这是确保可以存储在单个节点上最大输入块的大小。
3、reduce任务不具备数据本地化的优势
单个reduce任务的输入通常来自于所有mapper的输出。排过序的map输出需通过网络传输发送到运行reduce任务的节点,数据在reduce端合并并由用户定义的reduce函数处理。
四、MapReduce任务数据流
reduce任务的数量并非由输入数据的大小决定,而是独立指定的。
真实的应用中,几乎所有作业都会把reducer的个数设置成较大的数字,否则由于所有中间数据都会放到一个reduce任务中,作业的处理效率就会及其低下。
增加reducer的数量能缩短reduce进程;但是reducer数量过多又会导致小文件过多而不够优化。一条经验法则是:目标reducer保持每个运行在5分钟左右,且产生至少一个HDFS块的输出比较合适。
1、单个reduce任务的MapReduce数据流
虚线框表示节点,虚线箭头表示节点内部的数据传输,实线箭头表示不同节点之间的数据传输。
2、多个reduce任务的MapReduce数据流
map任务到reduce任务的数据流称为shuffle(混洗,类似洗牌的意思),每个reduce任务的输入都来自许多map任务。shuffle比图示的更加复杂而且调整shuffle参数对作业总执行时间的影响非常大。
3、无reduce任务
当数据完全可以并行处理时可能会出现无reduce任务的情况,唯一的非本地节点数据传输是map任务将结果写入HDFS。
五、combiner函数(减少map和reduce之间的数据传输)
由前面的描述我们知道数据传输会占用集群上的可用带宽资源,从而限制了MapReduce作业的数量,因此我们应该尽量避免map和reduce任务之间的数据传输。combiner作为一个中间函数简化map任务的输出从而减少了map任务和reduce任务之间的数据传输。
举个例子:
假设我们有一个计算每年最高气温的任务,1950年的读数由两个map任务处理(因为它们在不同的分片中)。假设第一个map的输出如下:
(1950,0)
(1950,20)
(1950,10)
第二个map的输出如下:
(1950,25)
(1950,15)
reduce函数调用时,输入如下:
(1950,[0,20,10,25,15)
reduce的输出如下:
(1950,25)
为了优化reduce函数的输入,我们可以使用combiner找到每个map任务输出结果中的最高气温。那么可以将reduce函数调用的输入更改为:
(1950,[20,25])
其中20和25为每个map函数输出结果中的最大值
我们可以用下面表达式来说明寻找最高气温的MapReduce过程中combiner的作用:
max(0,20,10,25,15) = max(max(0,20,10),max(25,15)) = max(20,25)=25
很遗憾,并非所有函数都具有该属性,比如计算平均值时就不能用mean作为combiner函数,因为:
mean(0,20,10,25,15) = 14
mean(mean(0,20,10),mean(25,15)) = mean(10,20) = 15
另外,combiner函数并不能取代reduce函数的位置,因为我们仍然需要reduce函数来处理不同map输出中具有相同键的记录。
写MapReduce程序(Hadoop streaming)
Hadoop Streaming使用Unix标准流作为Hadoop和应用程序之间的接口,允许程序员用多种语言写MapReduce程序。
Streaming天生适合于文本处理。map的输入数据通过标准输入传递给map函数,并且是一行一行地传输,并且将结果行写到标准输出。map输出的键-值对是以一个制表符分隔的行,reduce输入格式与之相同。reduce函数从标准输入流中读取输入行,该输入已经由Hadoop框架根据键排过序,最后将结果写入标准输出。
接下里我们用Streaming重写按年份查找最高气温的MapReduce程序。
Map函数
import re
import sys
for line in sys.stdin:
val = line.strip()
(year,temp,q) = (val[15:19],val[87:92],val[92:93])
if (temp != "+9999" and re.match("[01459]",q)
print ("%s\t%s" % (year,temp))
Reduce函数
import sys
(last_key,max_val) = (None,-sys.maxint)
for line in sys.stdin:
(key,val) = line.strip().split("\t")
if last_key and last_key != key:
print ("%s\t%s" % (last_key,max_val))
(last_key,max_val) = (key,int(val))
else:
(last_key,max_val = (key,max(max_val,int(val)))
if last_key:
print("%s\t%s" % (last_key,max_val))
示例3:
https://zhuanlan.zhihu.com/p/34903460
参考
https://zhuanlan.zhihu.com/p/62135686
https://zhuanlan.zhihu.com/p/32172999
https://zhuanlan.zhihu.com/p/55884610
https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html