partition实现
partition的作用是把环形缓冲区中的map输出分区存储,以便分配给不同的reducer。
把内部的实现写下来,作为一个学习笔记
- 在map函数,调用context.write()时,会去调用分区函数,得到分区号,把分区号一块写进keyvalue的元数据。
- 当环形缓冲区达到溢写磁盘时
- a) 对每个分区内的数据进行排序
- b) 把每个分区内的数据写到磁盘
下面通过代码来说明
1
context.write(K,V) -> MapTask.NewOutputCollector.write(K, V) -> MapOutputBuffer.collect(K, V, partion)
void MapTask.NewOutputCollector.write(K key, V value) {
collector.collect(key, value,
partitioner.getPartition(key, value, partitions)); // 调用分区函数
}
MapOutputBuffer.collect(K, V, partion) {
...
kvmeta.put(kvindex + PARTITION, partition); // 把分区号一块写进keyvalue元数据
...
}
2-a)
MapTask.MapOutputBuffer.flush()->MapTask.MapOutputBuffer.sortAndSpill()->IndexedSortable.compare(final int mi, final int mj)
void MapTask.MapOutputBuffer.sortAndSpill() {
...
sorter.sort(MapOutputBuffer.this, mstart, mend, reporter); // 对数据进行排序,默认采用快速排序。调用了下面的compare()方法
...
}
// 比较 mi和mj所对应的两个key,这个方法先比较分区号,如果分区号相同,才有必要比较key,实现了按各个分区内的key进行排序
public int MapTask.MapOutputBuffer.compare(final int mi, final int mj) {
final int kvi = offsetFor(mi % maxRec);
final int kvj = offsetFor(mj % maxRec);
final int kvip = kvmeta.get(kvi + PARTITION); // 从keyvalue元数据取出mi的分区号
final int kvjp = kvmeta.get(kvj + PARTITION); // 从keyvalue元数据取出mj的分区号
// sort by partition
if (kvip != kvjp) { // 如果分区号不相同,直接比较分区号:分区号的大小决定了写磁盘时的先后顺序
return kvip - kvjp;
}
// sort by key // 分区号相同,再比较key,这个方法调用RawComparator.compare(buffer, s1, l1, s2, l2);
return comparator.compare(kvbuffer,
kvmeta.get(kvi + KEYSTART), // key1的开始位置
kvmeta.get(kvi + VALSTART) - kvmeta.get(kvi + KEYSTART), // key1的结束位置
kvbuffer,
kvmeta.get(kvj + KEYSTART), //key2的开始位置
kvmeta.get(kvj + VALSTART) - kvmeta.get(kvj + KEYSTART)); // key2的开始位置
}
2-b)
a和b都是在sortAndSpill()中
void MapTask.MapOutputBuffer.sortAndSpill() {
...
sorter.sort(MapOutputBuffer.this, mstart, mend, reporter); // 对数据进行排序,默认采用快速排序。调用了下面的compare()方法
...
// 按分区号从小到大,一个分区一个分区写进磁盘
for (int i = 0; i < partitions; ++i) {
...
while (spindex < mend &&
kvmeta.get(offsetFor(spindex % maxRec) + PARTITION) == i) { // 从元数据读出kv分区号,如果是当前正在写磁盘的分区号,就把这个kv写到磁盘
final int kvoff = offsetFor(spindex % maxRec);
int keystart = kvmeta.get(kvoff + KEYSTART);
int valstart = kvmeta.get(kvoff + VALSTART);
key.reset(kvbuffer, keystart, valstart - keystart);
getVBytesForOffset(kvoff, value);
writer.append(key, value); // 把kv写到磁盘
++spindex;
}
}
...
}
经过上面这些步骤,环形缓冲区内的kv,就按分区写到磁盘,并且每个分区内的数据是有序的。
当然,这并不能保证同一个分区内,先后溢写的数据是有序的。后面使用归并排序对磁盘上的分区数据再做一轮排序,这个以后再做分析。
partition实现的更多相关文章
- Partition:增加分区
在关系型 DB中,分区表经常使用DateKey(int 数据类型)作为Partition Column,每个月的数据填充到同一个Partition中,由于在Fore-End呈现的报表大多数是基于Mon ...
- Partition:Partiton Scheme是否指定Next Used?
在SQL Server中,为Partition Scheme多次指定Next Used,不会出错,最后一次指定的FileGroup是Partition Scheme的Next Used,建议,在执行P ...
- Partition:分区切换(Switch)
在SQL Server中,对超级大表做数据归档,使用select和delete命令是十分耗费CPU时间和Disk空间的,SQL Server必须记录相应数量的事务日志,而使用switch操作归档分区表 ...
- sql 分组取最新的数据sqlserver巧用row_number和partition by分组取top数据
SQL Server 2005后之后,引入了row_number()函数,row_number()函数的分组排序功能使这种操作变得非常简单 分组取TOP数据是T-SQL中的常用查询, 如学生信息管理系 ...
- Oracle Partition Outer Join 稠化报表
partition outer join实现将稀疏数据转为稠密数据,举例: with t as (select deptno, job, sum(sal) sum_sal from emp group ...
- SQLServer中Partition By 函数的使用
今天群里看到一个问题,在这里概述下:查询出不同分类下的最新记录.一看这不是很简单的么,要分类那就用Group By;要最新记录就用Order By呗.然后在自己的表中试着做出来: 首先呢我把表中的数据 ...
- [LeetCode] Partition Equal Subset Sum 相同子集和分割
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- [LeetCode] Partition List 划分链表
Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...
- 快速排序中的partition函数的枢纽元选择,代码细节,以及其标准实现
很多笔试面试都喜欢考察快排,叫你手写一个也不是啥事.我很早之前就学了这个,对快速排序的过程是很清楚的.但是最近自己尝试手写,发现之前对算法的细节把握不够精准,很多地方甚至只是大脑中的一个映像,而没有理 ...
- [bigdata] kafka基本命令 -- 迁移topic partition到指定的broker
版本 0.9.2 创建topic bin/kafka-topics.sh --create --topic topic_name --partition 6 --replication-factor ...
随机推荐
- 移动开发 android 入门开发 阶段视频
一直想把 android 的开发学习录制成视频,这里录制了一部分供大家学习. http://www.chuanke.com/s5402069.html 到这里,文档,源码,视频基本就全了,祝愿大家能够 ...
- Ubuntu 12.04 gedit编辑器 中文乱码
百度一下查看了很多关于这个问题的解决方法,无非是用通过配置编辑器修改键值来解决.但是由于我的ubuntu是12.04版本的,搜索到的很多方法都不能用,网上一般的解决办法如下: 打开“注册表”(从字面理 ...
- github添加ssh认证
总概:在使用git的时候,和目标仓库建立关系有两种方式https,ssh.一般用的是https认证(这样简单方便),但有个缺点,pull,push等操作需要频繁输入用户验证.虽然可以把用户验证账号密码 ...
- Flash图表控件FusionCharts如何在图表中显示标识和图片
在FusionCharts的图表中显示外部商标 使用FusionCharts之后,用户可以在运行时加载需要在图表中显示的外部标识/图片/图像.这个标识可以GIF / JPEG / PNG或SWF文件格 ...
- kubernetes源码解析---- apiserver路由构建解析(1)
kubernetes源码解析---- apiserver路由构建解析(1) apiserver作为k8s集群的唯一入口,内部主要实现了两个功能,一个是请求的路由和处理,简单说就是监听一个端口,把接收到 ...
- cisco VPN配置
拓扑拿朋友的. r1(config)#int f0/0 r1(config-if)#ip add 50.50.50.50 255.255.255.0 r1(config-if)#no shu r1(c ...
- 第2章 linux文件系统
1.用户和用户组管理 1.1 用户管理常用命令 1.用户账号添加命令useradd或adduser 命令格式:useradd [option] [username] 其中[option]为userad ...
- jquery zTree 查找所有的叶子节点
jquery zTree 查找所有的叶子节点 // 保存所有叶子节点 10 为初始化大小,并非数组上限 var arrayObj = new Array([10]); /* treeNode: 根节点 ...
- 在使用 AjaxFileUpload 上传文件时,在项目发布到 iis 后,图片不能预览
在使用 AjaxFileUpload 上传文件时,图片已经上传成功了,在站点没有发布时,可以预览,可是在项目发布到 iis 后,图片就不能预览,在网上找了很多的方案也没解决,最后的解决方案如下: 1 ...
- C++三种内存分配方式
从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量.静态分配的区域的生命期是整个软件运行期,就是说从软件运行开始到软件终止退出.只 ...