Understanding Cubert Concepts(二):Cubert Co-Partitioned Blocks
话接上文Cubert PartitionedBlocks,我们介绍了Cubert的核心Block概念之一的分区块,它是一种根据partitionKeys
和cost function
来对原始数据进行Redistribution
和Transformation
来结构化数据,这种结构化的数据是对后续join和cube计算是非常有利的。
好了,本文将着重讲Cubert Block中的另一种Block,Co-PartitionedBlock.
Co-partitioned Blocks
让我们来看下另一种创建blocks的方式:
这种方式就是,依靠一个dataset的index
来创建``另一个dataset的blocks
.
比如:
有一个dataset P 是通过上文Cubert PartitionedBlocks的BLOCKGEN
方式生成的。这个dataset P 的内部会将partitionKeys的全局的range
划分为sub-ranges
,使得每个sub-range的key范围对应了一个block.(Ps:就是定范围的rangeKeys的数据在一个block内)
举个例子:
- BLOCKGEN For DataSet P (
PartitionedBlocks
)
比如我们对dataset P的parititionKey
指定为memberId,那么BLOCKGEN
过程后,会生成类似如下的索引:
memberIds from 0 to 1000 => block 0
memberIds from 1001 to 1500 => block 1
and so on until block N
至此,我们做的都是PartitionedBlocks
,如果dataset **S**
要生成Co-paritionedBlocks
怎么办呢? 那么索引
就是dataset **P**
.
- BLOCKGEN For DataSet S (
Co-partitionedBlocks
)
我们要生成与DataSet P 同样number
的blocks
。(分区都是一致的)
具体来说,就是block i of S
会和block i in P
有着相同的memberIds
,换句话说,如果memberId=1234
在block 2 of P
中,那么我们能确定能在block 2 of S
中找到这个相同的memberId
.
对于Map-Side Join
来说,这种一致性的分区方法
是必要的。
这种根据其它已经partitionedBlock来进行创建一致性分区Block的过程叫做BLOCKGEN BY INDEX
BLOCKGEN BY INDEX Checklist
如果想要使用cubert来进行开发,那么我们必须遵从下面三个准则:
- 定义primary relation:也就是上面我们创建的
DataSet P
,指定我们要使用的index,这样我们可以根据这个index来创建BLOCKS。(Ps:这里的说的index,就是primary relation)Note:
BLOCKGEN BY INDEX
是一个可传递性的操作,比如,我们有三个数据集A,B,C。我们通过BLOKGEN
操作数据集A,然后我们可以将A
作为primary relation (可以看做indexA)
,这样我们就可以根据indexA
创建co-partitioned Blocks
。现在如果C也要做BLOCKGEN
操作怎么办呢,选用A还是B呢?其实这种BLOCKGEN BY INDEX
是传递性的,indexA -> Blocks of B (co-partitioned), 那么indexA -> Blocks of C 后, Blocks of B == Blocks of C(这里==
的意思是co-partitioned).所以说
BLOCKGEN BY INDEX
是一个可传递性的操作。 - 定义SortKeys(可选)
这个排序也是在每个生成后的block内进行的(根据sortKeys排序),不是全局排序的。
- 存储为RUBIX FILE FORMAT
原始数据集转化为blocks的操作,存储的格式必须为RUBIX FILE FOMRAT。
Creating Co-Partitioned Blocks
要创建Co-PartitionedBlocks,还是需要BLOCKGEN
这个shuffle command,通过使用BY INDEX
来生成。
- 首先第一个JOB生成primary dataset(包含index,存储的路径就是下面要生成co-partitionedBlocks的索引路径)
- 第二个BlockGen是通过
BY INDEX
指定第primary dataset BLOCKGEN
的target path
为其索引的。
eg:
// the primary dataset
JOB "our first BLOCKGEN"
REDUCERS 10;
MAP {
data = LOAD "/path/to/data" USING AVRO();
}
//根据memberId来作为分区键,根据timestamp来进行sort
BLOCKGEN data BY ROW 1000 PARTITIONED ON memberId SORTED ON timestamp;
//注意,这里必须存储为RUBIX FILE FORMAT
STORE data INTO "/path/to/output" USING RUBIX();
END
JOB "our first blockgen by index"
REDUCERS 20;
MAP {
data = LOAD "/path/to/other/data" USING AVRO();
}
//注意 INDEX的 Path 为 上一个JOB的存储目录
BLOCKGEN data BY INDEX "/path/to/output" PARTITIONED ON memberId SORTED ON some_column;
STORE data INTO "/path/to/other/output" USING RUBIX();
END
Idiom of Resorting Blocks
BLOCKGEN BY INDE
命令还有另一种用途,对于已创建过的Blocks进行重新排序
在上一个例子里的our first BLOCKGEN
JOB里,我们是对blocks内部根据timestamp键来进行排序的。如果我想重新指定排序键,怎么做呢?
- 将生成Blocks后的数据集重新从存储路径(
/path/to/output
)使用RUBIX FILE FORMAT加载进来 - 使用相同的路径自引用索引
/path/to/output
来BLOCKGEN BY INDEX
,并且指定sorted on pagekey
重排序的键为pagekey
JOB "resorting blocks"
REDUCERS 10;
MAP {
data = LOAD "/path/to/output" USING RUBIX();
}
BLOCKGEN data BY INDEX "/path/to/output" PARTITIONED ON memberId SORTED ON pagekey;
STORE data INTO "/path/to/resorted-output" USING RUBIX();
END
注意:
- 我们要确保使用的还是原始数据集的index
- 并且一定要使用相同的
partition Keys
哦,否则block的数据分布就乱了。
同样,我们可以对数据集B,C都使用indexA进行重排序处理,因为他们都是co-partitioned blocks
参考
Ps:本文的写作是基于对Cubert官方文档的翻译和个人对Cubert的理解综合完成 :)
原创文章,转载请注明:
转载自:OopsOutOfMemory盛利的Blog,作者: OopsOutOfMemory
本文链接地址:http://blog.csdn.net/oopsoom/article/details/46707733
注:本文基于署名-非商业性使用-禁止演绎 2.5 中国大陆(CC BY-NC-ND 2.5 CN)协议,欢迎转载、转发和评论,但是请保留本文作者署名和文章链接。如若需要用于商业目的或者与授权方面的协商,请联系我。