0)一份数据上传到hdfs中,会被切分成好多片(比如64MB),并且每一个片段会存到若干台DataNode(冗余存储,防止某个节点失效后不至于导致数据不完整,作业无法进行)
1)map的输出既是Reduce的输入。
2)map对每条记录的输出以<key,value> pair的形式输出。
3)在进入reduce阶段之前,还要将各个map中相关的数据(key相同的数据)进过洗牌,排序,归结到一起,发往一个reducer。
4) 进入reduce阶段,相同的key的map输出会到达同一个reducer
MapReduce 程序是设计用来并行计算大规模海量数据的,这需要把工作流分划到大量的机器上去,如果组件(component)之间可以任意的共享数据,那这个模型就没 法扩展到大规模集群上去了(数百或数千个节点),用来保持节点间数据的同步而产生的通信开销会使得系统在大规模集群上变得不可靠和效率低下。
实际上,所有在MapReduce上的数据元素都是不可变的,这就意味着它们不能够被更新。如果在一个mapping任务中你改变了一个输入键值对,它并 不会反馈到输入文件;节点间的通信只在产生新的输出键值对((key,value)pairs)时发生,Hadoop系统会把这些输出传到下一个执行阶 段。
列表处理(List Processing)
从概念上讲,MapReduce程序转变输入数据元素列表成输出数据元素列表。一个MapReduce程序会重复这个步骤两次,并用两个不同的术语描述:map和reduce,这些术语来自于列表处理语言,如:LISP,Scheme,或ML。
Mapping数据列表(Lists)
MapReduce程序的第一步叫做mapping,在这一步会有一些数据元素作为Mapper函数的输入数据,每次一个,Mapper会把每次map得到的结果单独的传到一个输出数据元素里。
![mapreduce简单原理 - Leo - 好记性不如烂笔头---Leo](http://img.ph.126.net/YeysH7DyM3OJfZRop8bKlQ==/633318697615836347.png)
Mapping通过对输入数据列表中的每一个元素应用一个函数创建了一个新的输出数据列表
这里举一个map功能的例子:假设 你有一个函数toUpper(str),用来返回输入字符串的大写版本。你可以在map中使用这个函数把常规字符串列表转换成大写的字符串列表。注意,在 这里我们并没有改变输入字符串:我们返回了一个新的字符串,它是新的输出列表的组成部分之一。
Reducing数据列表(Lists)
Reducing可以让你把数据聚集在一起。reducer函数接收来自输入列表的迭代器,它会把这些数据聚合在一起,然后返回一个输出值。
![mapreduce简单原理 - Leo - 好记性不如烂笔头---Leo](http://img.ph.126.net/J1lVuuIZbV1pAiFTZ2S4zw==/1148136430019625450.png)
通过列表迭代器对输入数据进行reducing操作来输出聚合结果。
Reducing一般用来生成”总结“数据,把大规模的数据转变成更小的总结数据。比如,"+"可以用来作一个reducing函数,去返回输入数据列表的值的总和。
把它们一起放在MapReduce中
Hadoop的MapReduce框架使用了上面的那些概念并用它们来处理大规模的数据信息。MapReduce程序有着两个组件:一个实现了 mapper,另一个实现了reducer。上面描叙的Mapper和Reducer术语在Hadoop中有了更细微的扩展,但基本的概念是相同的。
键和值:在MapReduce中,没有一个值是单独的,每一个值都会有一个键与其关联,键标识相关的值。举个例子,从多辆车中读取到的时间编码车速表日志可以由车牌号码标识,就像下面一样:
AAA-123 65mph, 12:00pm
ZZZ-789 50mph, 12:02pm
AAA-123 40mph, 12:05pm
CCC-456 25mph, 12:15pm
...
mapping和reducing函数不是仅接收数值(Values),而是(键,值)对。这些函数的每一个输出都是一样的:都是一个键和一个值,它们将被送到数据流的下一个列表。
对于Mapper和Reducer是如何工作的,MapReduce没有像其它语言那样严格。在更正式的函数式mapping和reducing设置 中,mapper针对每一个输入元素都要生成一个输出元素,reducer针对每一个输入列表都要生成一个输出元素。但在MapReduce中,每一个阶 段都可以生成任意的数值;mapper可能把一个输入map为0个,1个或100个输出。reducer可能计算超过一个的输入列表并生成一个或多个不同 的输出。
根据键划分reduce空间:reducing函数的作用是把大的数值列表转变为一个(或几个)输出数值。在MapReduce 中,所有的输出数值一般不会被reduce在一起。有着相同键的所有数值会被一起送到一个reducer里。作用在有着不同键关联的数值列表上的 reduce操作之间是独立执行的。
![mapreduce简单原理 - Leo - 好记性不如烂笔头---Leo](http://img.ph.126.net/mzr_zXjuSW2WSN5zn48FqQ==/2765773121175766380.png)
不同颜色代表不同的键,有着相同键的数值都被传到同一个reduce任务里。
应用例子:词频统计(Word Count)
写一个简单的MapReduce程序就可以用来统计不同的词在一个文件集中出现的次数。比如,我们有这样的文件:
foo.txt: Sweet, this is the foo file
bar.txt: This is the bar file
我们期望输出会是这样子:
sweet 1
this 2
is 2
the 2
foo 1
bar 1
file 2
当然没问题,我们可以写一个MapReduce程序来计算得到这个输出。高层结构看起来会是这样子:
mapper (filename, file-contents):
for each word in file-contents:
emit (word, 1)
reducer (word, values):
sum = 0
for each value in values:
sum = sum + value
emit (word, sum)
列表4.1 MapReduce词频统计伪代码
若干个mapper函数的实例会被创建在我们的集群的不同机器上,每个实例接收一个不同的输入文件(这里假设我们有很多个文件)。 mappers输出的(word,1)键值对会被转到reducers那里去。若干个reducer方法实例也会在不同机子上被实例化。每个 reducer负责处理关联到不同词的数值列表,数值列表中的值都是1;reducer把这些“1”值总和到一个关联了某个词的最终计数里。 reducer然后生成最终的(word,count)输出,并把它写到一个输出文件里。
原文地址:http://blog.163.com/clevertanglei900@126/blog/static/1113522592011787857347/
c++代码:
examples:单词统计
#include <algorithm>
#include <limits>
#include <string>
#include "stdint.h" // <--- to prevent uint64_t errors!
#include "hadoop/Pipes.hh"
#include "hadoop/TemplateFactory.hh"
#include "hadoop/StringUtils.hh"
using namespace std;
class WordCountMapper : public HadoopPipes::Mapper {
public:
// constructor: does nothing
WordCountMapper( HadoopPipes::TaskContext& context ) {
}
// map function: receives a line, outputs (word,"1")
// to reducer.
void map( HadoopPipes::MapContext& context ) {
//--- get line of text ---
string line = context.getInputValue();
//--- split it into words ---
vector< string > words =
HadoopUtils::splitString( line, " " );
//--- emit each word tuple (word, "1" ) ---
for ( unsigned int i=0; i < words.size(); i++ ) {
context.emit( words[i], HadoopUtils::toString( 1 ) );
}
}
};
class WordCountReducer : public HadoopPipes::Reducer {
public:
// constructor: does nothing
WordCountReducer(HadoopPipes::TaskContext& context) {
}
// reduce function
void reduce( HadoopPipes::ReduceContext& context ) {
int count = 0;
//--- get all tuples with the same key, and count their numbers ---
while ( context.nextValue() ) {
count += HadoopUtils::toInt( context.getInputValue() );
}
//--- emit (word, count) ---
context.emit(context.getInputKey(), HadoopUtils::toString( count ));
}
};
int main(int argc, char *argv[]) {
return HadoopPipes::runTask(HadoopPipes::TemplateFactory<
WordCountMapper,
WordCountReducer >() );
}