Hadoop权威指南-大数据的存储与分析第四版——学习笔记——第2章——1

MapReduce

适合处理半结构化的数据

MapReduce任务阶段

Map阶段+Reduce阶段
Key-Value作为输入输出
实现两个函数:map(),reduce()

Map阶段

输入的Key:文本中的偏移量
输入的value:文本
输出的k-v给reduce处理

Reduce阶段

基于key对k-v对进行 排序分组
例如:
输入数据(文本):在这里插入图片描述
map输入:
在这里插入图片描述
map输出:
在这里插入图片描述
reduce输入(注:这里的输入是分组、排序后的,key为年份,value为List):
在这里插入图片描述
reduce输出(找出每年里的最高温度/最大数值):
在这里插入图片描述
整个数据流程图如下:
在这里插入图片描述

Java MapReduce

注: Mapper和Reducer类都是抽象类,需要实现其map,reduce抽象方法
1)需要导入的包——org.apache.hadoop下的包,包括:
org.apache.hadoop.mapreduce.Mapper/.Reducer
org.apaceh.hadoop.io.IntWritable/.LongWritable/.Text
2)Map类需要extends Mapper<四个输入输出格式参数类型>,实现map(四个输入输出格式参数)函数,返回值为void,这里的map函数的参数可以为 :
输入key,输入value,Context/Mapper<输出key,输出value>.Context
3)Reduce类需要extends Reduce<四个输入输出格式参数类型>,实现reduce(输入key类型 key,输入Iterable<value类型> value,Context/Reducer<输出key,输出value>.Context)
4) 只要实现了Iterable接口的对象都可以使用for-each循环
public interface Iterable {
Iterator iterator();
}
关于hadoop reduce阶段遍历Iterable的注意事项
只能遍历一次(对象重用:输入key和输入value对象只有一对,反复利用,所以要想重复遍历这两个对象,尤其是第二个iterable,就要clone一下;当初一直在想为什么用iterable不用iterator呢,现在发现iterable接口的iterator() 方法返回的是一个特殊的迭代器,他原则上不允许迭代两次及以上,若迭代两次及以上则会返回空值,因为对象重用,reduce阶段输入的value值不一定都在内存内,可能还要从磁盘上读取,所以hadoop不允许对接受到的value迭代器重复遍历,现在大概理解到这个层面上,具体是不是因为java对于iterable的机制就是这样我也不太清楚,之后再来加深了解吧。(ps:昨天查了下java的iterable和iterator,有了新的了解,也想到了reduce阶段输入的参数可能是hadoop定义了一个类,这个类还不知道是什么反正是实现好了iterable和iterator的接口,然后创建这个类的对象读取输入的value值,并作为参数传给reduce函数) 最后附上Stack Overflow上的解答:
The Iterator you receive from that Iterable’s iterator() method is special. The values may not all be in memory; Hadoop may be streaming them from disk. They aren’t really backed by a Collection, so it’s nontrivial to allow multiple iterations.

for(Text val : values) {
valList.add(val.toString());
textList.add(val);
}
这个部分第一次val.toString()得到的每个k-v对中不同的value值,但是第二次add(val)进去的却一直是最后一个k-v对的值,这是因为add方法传递的是对象的地址,因为上文的value对象一直在被复用,所以第二次遍历的时候,他一直指向最后一个k-v对
ps这里如果处理更大规模的数据,会不会因为reduce阶段处理时间太长而导致复用的value对象还没用读到最后一个k-v对,而是其他k-v对的值,然后textList中的对象地址指向的并不是最后一个k-v对?
我觉得可能会,因为shuffling阶段从map节点上merge的最终输入文件可能因为太大而存在了磁盘上,而且默认也是存在磁盘上的,这个参照博客 https://blog.csdn.net/mrlevo520/article/details/76781186 数据量过大导致内存中的value放不下,就必须读一批value然后reduce处理一下,再释放内存中的value,再从磁盘读,再reduce处理,知道最后处理完成,这样的话就有可能发生上述的情况。)
https://blog.csdn.net/jdbc/article/details/38850961
1、需要三个东西:map函数 reduce函数 运行作业的代码
Java Context类:类似于放信息的容器
2、org.apache.hadoop.io包中提供了一套可优化网络序列化的基本类型,例如:IntWritable,LongWritable,Text
注: String类的substring(int beginIndex,int endIndex)方法,截取子串
beginIndex:起始索引(包括),索引从0开始;
endIndex:结束索引(不包括

猜你喜欢

转载自blog.csdn.net/Mr_Effiya/article/details/84236473