DetermineHashedPartitionsJob


功能:

这个任务使用HyperLogLog基数统计方法,通过计算输入数据基数,从而产生合适的ShardSpecs。

Hadoop Index任务IndexGeneratorJob任务就是通过ShardSpecs判断reducer个数等一系列任务属性。

两个阶段:

一、【MR任务】阶段,根据timestamp和dimension计算每个Interval区间的数据量

二、【Load partitions and intervals】阶段,根据MR任务产生的结果,构建List<HadoopyShardSpec>


【Druid】DetermineHashedPartitionsJob源码解析_druid

一、【MR任务】阶段

目标:MapReducer的目标是基于HLL算法,统计数据量在Intervals时间区间的分布情况。所以DetermineHashedPartitionsJob中MR任务输出是Interval区间以及每个区间的数据量<Interval目录,预估基数值>。

1、在DetermineHashedPartitionsJob流程中的MapReduce任务结束后,会以Intervals生成多个目录,每个目录下有partition.json,保存着当前interal的数据量。

关键步骤,如流程图中上半部,

  • 创建Job Name
  • 设置Mapper、Reducer、Partitioner等
  • 判断是否配置Interval参数
  • 设置Reducer Num大小


DetermineCardinalityMapper类:

由名字可以看出这个类主要功能是计算输入数据基数

把DetermineCardinalityMapper分成三部分看

1、形成groupKey,由timestamp和inputRow构成

final List<Object> groupKey = Rows.toGroupKey(
rollupGranularity.bucketStart(inputRow.getTimestamp()).getMillis(),
inputRow
);

2、由hyperLogLogs统计每个interval的数据量

hyperLogLogs
.get(interval)
.add(hashFunction.hashBytes(HadoopDruidIndexerConfig.JSON_MAPPER.writeValueAsBytes(groupKey)).asBytes());

3、Mapper的输出格式<interval开始时间戳,该interval的数据量>

for (Map.Entry<Interval, HyperLogLogCollector> entry : hyperLogLogs.entrySet()) {
context.write(
new LongWritable(entry.getKey().getStartMillis()),
new BytesWritable(entry.getValue().toByteArray())
);
}
DetermineCardinalityReducer类

中间逻辑比较简单,直接看reducer输出,<Interval目录,预估基数值>

HadoopDruidIndexerConfig.JSON_MAPPER
.writerWithType(Long.class)
.writeValue(out, aggregate.estimateCardinalityRound());
log.info("文件名:%s, 数据值:%s", outPath.toString(), aggregate.estimateCardinalityRound());


二、【Load partitions and intervals】阶段:

目标:生成下游使用的GranularitySpec配置

关键步骤,如流程图中下半部分

  • 判断是否配置Interval参数
  • 未配置Interval参数,通过MR输出的Interval目录,生成interval.json配置文件,基于此创建GranularitySpec
  • 基于GranularitySpec配置读取每个Interval目录下partition.json
  • 计算numberOfShard

计算numberOfShard的公式,假设数据总行数numRows=100,配置targetPartitionSize=30,则numberOfShards=4。

最终形成的4个Segment,每个Segment有25行数据

final int numberOfShards = (int) Math.ceil((double) numRows / config.getTargetPartitionSize());


  • 生成shardSpec

【Load partitions and intervals】阶段,若没有配置GranularitySpec.Interval的情况下,会通过上一步MR任务产生的Intervals目录,形成interval.json。interval.json保存各个Intervals区间,例如["2011-04-10T00:00:00.000Z/2011-04-11T00:00:00.000Z","2011-04-11T00:00:00.000Z/2011-04-12T00:00:00.000Z","2011-04-12T00:00:00.000Z/2011-04-13T00:00:00.000Z"]。

然后通过这些Intervals创建GranularitySpec配置。

根据GranularitySpec,形成List<HadoopyShardSpec>。后续将根据List<HadoopyShardSpec>生成数据处理任务


DetermineHashedPartitionsJob生成的结果文件

Interval区间目录:


[mymac@16:33:57]/var/folders/pv/dkqbk3wj51b7yb4r5wd9qgdw0000gn/T/druid1556516960499050846/test_schema/2021-08-18T082845.340Z_03142bf7483b4a39a53db168f0d71501$ ll
total 0
drwxr-xr-x 3 mymac staff 96 8 18 16:28 groupedData
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110410T000000.000Z_20110411T000000.000Z
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110411T000000.000Z_20110412T000000.000Z
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110412T000000.000Z_20110413T000000.000Z
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110413T000000.000Z_20110414T000000.000Z
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110414T000000.000Z_20110415T000000.000Z
drwxr-xr-x 4 mymac staff 128 8 18 16:28 20110415T000000.000Z_20110416T000000.000Z

其中一个Interval下的数据量,保存在partitions.json文件中

[mymac@16:33:23]/var/folders/pv/dkqbk3wj51b7yb4r5wd9qgdw0000gn/T/druid1556516960499050846/test_schema/2021-08-18T082845.340Z_03142bf7483b4a39a53db168f0d71501/20110410T000000.000Z_20110411T000000.000Z$ ll
total 8
-rw-r--r-- 1 mymac staff 2 8 18 16:28 partitions.json
[mymac@19:05:42]/var/folders/pv/dkqbk3wj51b7yb4r5wd9qgdw0000gn/T/druid1556516960499050846/test_schema/2021-08-18T082845.340Z_03142bf7483b4a39a53db168f0d71501/20110410T000000.000Z_20110411T000000.000Z$ cat partitions.json
13


疑问:

interval.json,partition.json什么时候生成的?

partition.json是MR产生的结果文件保存在某个Interval目录下,存储数据是该Interval的数据量

interval.json在配置文件中没有配置Interval的情况下,DetermineHashedPartitionsJob会根据MR产生的Intervals目录,构建interval.json,保存的就是Interval集合

Mapper,Reducer逻辑是什么,Reducer最终输出什么?

Reducer输出partition.json,输出<Interval目录,预估基数值>