Map阶段(MapTask): 切片(Split)-----读取数据(Read)-------交给Mapper处理(Map)------分区和排序(sort)
Reduce阶段(ReduceTask): 拷贝数据(copy)------排序(sort)-----合并(reduce)-----写出(write)
1、Map task读取:
框架调用InputFormat类的子类读取HDFS中文件数据,把文件转换为InputSplit。
默认,文件的一个block对应一个InputSplit,一个InputSplit对应一个map task。
一个InputSplit中的数据会被RecordReader解析成<k1,v1>。
默认,InputSplit中的一行解析成一个<k1,v1>。
默认,v1表示一行的内容,k1表示偏移量。
map:
框架调用mapper 类中的map方法,接收<k1,v1>输出<k2,v2>,有多少个<k1,v1>,就执行多少次map分区: 框架对mapp的输出进行分区,分区的目的是确定哪些<k2,v2>进入哪个reduce task。默认只有一个分区。
排序分组:框架对不同分区中的<k2,v2>进行排序分组.排序是按照k2进行排序。分组指的是相同k2的v2分到一个组中。分组不会减少<k2,v2>的数量。(快速排序)
combiner:可以在map task中对<k2,{v2}>执行reduce归约。
写入本地:框架对map的输出写入到Linux本地磁盘
2、reduce taskshuffle:
框架根据map不同分区中的数据,通过网络copy到不同的reduce节点合并
排序分组:每个reduce会把多个map传来的<k2,{v2}>进行合并排序分组(归并排序)
reduce:框架调用reduce<k2,v2s>,有多少个分组就回执行多少回reduce
写入HDFS:
框架对reduce输出的数据写入到hdfs中
快速排序:
个人理解:
就是归位,分区,递归
比如: 4,6,9,2,1,3,8 这个数组,要对它使用快速排序
首先,选第一个 4 对它进行归位 ,依次和4进行比较得到
左边: 2,1,3
右边:6,9,8
这样我们就的得到了 2,1,3,4 ,6,9,8
然后在对两边进行递归的操作。
python 实现
python
def partition(li, left, right):
tmp = li[left]
# 当两边搜索并没有重合的时候就进行双向查找
while left < right:
# 这一级两个判断条件
# 因为li[right] >= tmp退出说明在right出找到了小于tmp的值,这样填到left就行了
# 因为left < right退出是因为left右侧的所有值都大于tmp,left已经和right重合了
while left < right and li[right] >= tmp: # left有空缺,需要right小于tmp的值来填补
right = right - 1 # 往前一位接着找
li[left] = li[right] # 将右边的数写到左边空缺处
# 找到之后,right出现空缺,应从left找比tmp大的数填到right
while left < right and li[left] <= tmp:
left = left + 1
li[right] = li[left]
# 当双向查找两边重合时侯,left=right,将值写入
li[left] = tmp
return li
li = [5, 7, 4, 6, 3, 1, 2, 9, 8]
result = partition(li, 0, len(li)-1)
print(result)
def quick_sort(li, left, right):
if left < right: # 至少两个元素
mid = partition(li, left, right)
# 拿到mid之后就能对两边的部分进行相同的整理
quick_sort(li, left, mid-1)
quick_sort(li, mid+1, right)
li = [5,7,4,6,3,1,2,9,8]
quick_sort(li, 0, len(li)-1)
归并排序:
是将数组按 left mid right 划分成两个部分,要求每个部分是有序的,然后假设有两个指针指在,两个部分的第一个位置,开始比较,较小的被放到一个临时集合中,指针移动到下一个位置,然后继续比较,直到一方没有下一个值 ,另一方剩下的就是最大的一部分直接放在临时集合最后,整个排序完成。
python 实现
python
# 实现一次归并的过程
# 前提是已经拿到两个有序子的列表
def merge(li, low, mid, high):
"""
:param li:列表
:param low:第一段有序子列表起始位
:param mid:第一段有序子列表终止位
:param high:第二段有序子列表终止位
:return:一次归并操作之后的整个列表
"""
# i,j开始分别指向两个有序子序列的起始位
i = low
j = mid + 1
ltmp = [] # 存储结果用
while i<=mid and j<=high: # 只要两个有序子序列都有数
if li[i] < li[j]:
ltmp.append(li[i])
i = i + 1
else:
ltmp.append(li[j])
j = j + 1
# 两部分中有一部分拿光了
while i <= mid: # 说明后面的拿光了
ltmp.append(li[i])
i = i + 1
while j <= high: # 说明前面的拿光了
ltmp.append(li[j])
j = j + 1
li[low:high+1] = ltmp # 将结果写回去
li = [0,2,4,6,8,1,3,5,7,9]
merge(li, 0, 4, len(li)-1)