MapReduce是Google提出的一个软件架构,用于大规模数据集(大于1TB)的并行运算。概念“Map(映射)”和“Reduce(归纳)”
映射和归纳
- 映射
一个映射函数就是对一些独立元素组成的概念上的列表(例如,一个测试成绩的列表)的每一个元素进行指定的操作(比如,有人发现所有学生的成绩都被高估了一分,他可以定义一个“减一”的映射函数,用来修正这个错误。)。事实上,每个元素都是被独立操作的,而原始列表没有被更改,因为这里创建了一个新的列表来保存新的答案。这就是说,Map操作是可以高度并行的,这对高性能要求的应用以及并行计算领域的需求非常有用。 - 归纳
归纳操作指的是对一个列表的元素进行适当的合并(继续看前面的例子,如果有人想知道班级的平均分该怎么做?他可以定义一个归纳函数,通过让列表中的奇数(odd)或偶数(even)元素跟自己的相邻的元素相加的方式把列表减半,如此递归运算直到列表只剩下一个元素,然后用这个元素除以人数,就得到了平均分)。虽然他不如映射函数那么并行,但是因为归纳总是有一个简单的答案,大规模的运算相对独立,所以归纳函数在高度并行环境下也很有用。
Map/Reduce框架运转在<key, value> 键值对上,也就是说, 框架把作业的输入看为是一组<key, value> 键值对,同样也产出一组 <key, value> 键值对做为作业的输出,这两组键值对的类型可能不同。
框架需要对key和value的类(classes)进行序列化操作, 因此,这些类需要实现 Writable接口。 另外,为了方便框架执行排序操作,key类必须实现 WritableComparable接口。
一个Map/Reduce 作业的输入和输出类型如下所示:
(input) <k1, v1> -> map -> <k2, v2> -> combine -> <k2, v2> -> reduce -> <k3, v3> (output)
应用程序通常会通过提供map和reduce来实现 Mapper和Reducer接口,它们组成作业的核心。
Mapper
public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable>
1. Mapper组件开发方式:自定义一个类,继承Mapper
2. Mapper组件的作用是定义每一个MapTask具体要怎么处理数据。例如一个文件,256MB,会生成2个MapTask(每个切片大小,默认是128MB,所以MapTask的多少有处理的数据大小来决定)。即2个MapTask处理逻辑是一样的,只是每个MapTask处理的数据不一样。
3.下面是Mapper类中的4个泛型含义:
a.泛型一:KEYIN: Longwritable,对应的Mapper的输入key。输入key是每行的行首偏移里
b.泛型二: VALUEIN: Text,对应的Mapper的输入Value。输入value是每行的内容
c.泛型三:KEYOUT: 对应的Mapper的输出key,根据业务来定义
d.泛型四:VALUEOUT:对应的Mapper的输出value,根据业务来定义
4.注意:初学时,KEYIN和VALUEIN写死(LongWritable,Text)。KEYOUT和VALUEOUT不固定,根据业务来定
5.Writable机制是Hadoop自身的序列化机制,常用的类型:
a. LongWritable
b. Text(String)
c. IntWritable
d. NullWritable
6.定义MapTask的任务逻辑是通过重写map()方法来实现的。
读取一行数据就会调用一次此方法,同时会把输入key和输入value进行传递
7.在实际开发中,最重要的是拿到输入value(每行内容)
8. 输出方法:通过context.write(输出key,输出value)
9.开发一个MapReduce程序(job),Mapper可以单独存储,
此时,最后的输出的结果文件内容就是Mapper的输出。
10. Reducer组件不能单独存在,因为Reducer要依赖于Mapper的输出。
当引入了Reducer之后,最后输出的结果文件的结果就是Reducer的输出。
Reducer
public static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable>
1. Reducer组件用于接收Mapper组件的输出
2.reduce的输入key,value需要和mapper的输出key,value类型保持一致
3.reduce的输出key,value类型,根据具体业务决定
4.reduce收到map的输出,会按相同的key做聚合,
形成:key Iterable 形式然后通过reduce方法进行传递
5.reduce方法中的Iterable是一次性的,即遍历一次之后,再遍历,里面就没有数据了。
所以,在某些业务场景,会涉及到多次操作此迭代器,处理的方法是
:@先创建一个List @把Iterable装到List @多次去使用List即可
----------------
Hadoop中的Mapper是MapReduce编程模型中的一个组件,用于将输入数据划分为一系列键值对,并对每个键值对进行处理。Mapper负责处理输入数据的切分、映射和中间结果的输出。
Mapper类在Hadoop中是一个抽象类,需要用户自定义一个继承自Mapper类的子类,并实现其map方法。map方法的签名如下:
其中,KEYIN表示输入键的类型,VALUEIN表示输入值的类型,Context是Mapper的上下文对象,用于与Hadoop框架进行交互。
在map方法中,用户可以根据输入键值对的内容进行处理,并使用Context对象将中间结果输出。通常情况下,Mapper的输出键值对类型与输入键值对类型不同,可以通过泛型参数指定输出键值对的类型。例如,可以将输入的文本行切分为单词,并将每个单词作为键,将计数1作为值进行输出。
以下是一个简单的Mapper示例,它将输入的文本行切分为单词,并输出每个单词的计数为1:
在上述示例中,我们自定义了一个继承自Mapper类的子类MyMapper,并重写了map方法。在map方法中,我们首先将输入的Text类型的value转换为字符串,然后使用空格进行分词,将每个单词作为键,将计数1作为值进行输出。
需要注意的是,Mapper的输入可以是任意类型的键值对,用户需要根据实际情况指定输入键值对的类型,并根据输入数据的格式和处理逻辑编写map方法的实现。Mapper的输出会作为中间结果传递给Reducer进行进一步处理。
Hadoop中的Reducer是MapReduce编程模型中的一个组件,用于对Map阶段的输出进行合并和聚合操作,生成最终的输出结果。Reducer接受来自Mapper阶段的键值对数据集,并按照键进行分组,然后对每个键的值集合进行处理。
Reducer类在Hadoop中是一个抽象类,需要用户自定义一个继承自Reducer类的子类,并实现其reduce方法。reduce方法的签名如下:
其中,KEYIN表示输入键的类型,VALUEIN表示输入值的类型,Context是Reducer的上下文对象,用于与Hadoop框架进行交互。
在reduce方法中,用户可以通过迭代器Iterable<VALUEIN> values来遍历当前键的所有值,并对这些值进行处理。Reducer的输出可以使用Context对象的write方法写入最终的输出。
以下是一个简单的Reducer示例,它将输入的键值对进行合并,并计算每个键的总和:
在上述示例中,我们自定义了一个继承自Reducer类的子类MyReducer,并重写了reduce方法。在reduce方法中,我们遍历了每个键的所有值,并将它们累加到变量sum中,然后将结果写入输出。
需要注意的是,Reducer的输入键值对是按照键进行分组的,因此在reduce方法中,可以假设所有具有相同键的值都会被传递给同一个reduce方法进行处理。用户需要根据实际需求编写reduce方法的逻辑,对值进行合并、计算或其他操作,生成最终的输出结果。
重写Mapper方法
protected void map(LongWritable key, Text value,Mapper<LongWritable, Text, Text,FlowBean>.Context context)throws IOException,InterruptedException {
}
//Mapper<LongWritable,Text, Text,FlowBean>.Context context 表示上下文工具,用于将数据返回worker
Hadoop中Context类的作用和Mapper<LongWritable, Text, Text, LongWritable>.Context context
Mapper<LongWritable, Text, Text, LongWritable>.Context
在MapReduce中,Mapper类的context参数是用于与MapReduce框架进行交互的上下文对象。它提供了访问Mapper的输入和输出以及其他与作业执行相关的信息的方法。
在给定的代码示例中,Mapper的输入键类型为LongWritable,输入值类型为Text,输出键类型为Text,输出值类型为LongWritable。因此,context参数的类型应该是Mapper<LongWritable, Text, Text, LongWritable>.Context。
通过context对象,可以执行以下操作:
-
获取输入数据:可以使用context对象的方法获取当前Mapper正在处理的输入键值对。例如,可以使用context.getCurrentKey()获取当前输入键的值,使用context.getCurrentValue()获取当前输入值的值。
-
发出输出数据:可以使用context对象的方法将Mapper的输出键值对发送到Reducer或输出。例如,可以使用context.write(key, value)方法发送输出键值对。
-
记录日志:可以使用context对象的方法记录日志消息。例如,可以使用context.getCounter()获取计数器对象,并使用计数器对象的方法增加计数器的值。
-
获取配置信息:可以使用context对象的方法获取作业的配置信息。例如,可以使用context.getConfiguration()获取作业的配置对象,并使用配置对象的方法获取作业的参数。
总之,context参数提供了与MapReduce框架进行交互的方法和功能,使Mapper能够处理输入数据并生成输出数据。
在MapReduce中,Reducer类的reduce方法的签名通常如下所示:
这个方法用于对Mapper的输出进行聚合和处理,并生成最终的输出结果。下面是对这个方法的参数进行解释:
Text k2
:表示输入键的类型。在这个方法中,它表示Mapper的输出键类型。Iterable<LongWritable> v2s
:表示输入值的类型。在这个方法中,它表示Mapper的输出值类型的集合,因为一个键可能对应多个值。Reducer<Text, LongWritable, Text, LongWritable>.Context context
:表示与MapReduce框架进行交互的上下文对象。
通过这个方法,可以对相同键的值进行迭代,并进行聚合、计算或其他操作。在Reducer中,可以使用context对象来执行以下操作:
-
发出输出数据:可以使用context对象的方法将Reducer的输出键值对发送到最终的输出。例如,可以使用context.write(key, value)方法发送输出键值对。
-
记录日志:可以使用context对象的方法记录日志消息。例如,可以使用context.getCounter()获取计数器对象,并使用计数器对象的方法增加计数器的值。
-
获取配置信息:可以使用context对象的方法获取作业的配置信息。例如,可以使用context.getConfiguration()获取作业的配置对象,并使用配置对象的方法获取作业的参数。
总之,reduce方法通过迭代输入值的集合,对相同键的值进行聚合和处理,并将结果发送到最终的输出。context参数提供了与MapReduce框架进行交互的方法和功能,使Reducer能够生成最终的输出结果。
------------------
以下是一个完整的MapReduce WordCount代码示例,使用Java编写,并使用Hadoop作为MapReduce框架:
上述代码示例中的TokenizerMapper
类是Mapper类,它继承自Hadoop的Mapper
类,并重写了map
方法。在map
方法中,输入的文本被拆分为单词,并为每个单词发射一个键值对(单词, 1)。
IntSumReducer
类是Reducer类,它继承自Hadoop的Reducer
类,并重写了reduce
方法。在reduce
方法中,相同单词的计数被累加为总计数,并发射一个键值对(单词, 总计数)。
在main
方法中,首先创建一个Hadoop作业(Job
)对象,并设置作业的相关配置。然后,指定Mapper类和Reducer类,以及输入路径和输出路径。最后,运行作业并等待完成。
请注意,上述代码示例是使用Java编写的,并使用Hadoop作为MapReduce框架。您需要在Hadoop集群上配置和运行此代码。具体的配置和运行步骤可能因环境而异