我在a question上读过:
我遇到了一个Hive查询,该查询计算没有分组的不同计数, 运行非常慢。所以我想知道此功能如何 在Hive中实施,是否为此有UDAFCountDistinct?
答案:
要获得不同的计数,Hive依赖于GenericUDAFCount。那里 没有专门针对计数不同而实施的UDAF。那些 “与众不同”键将成为 MapReduce Shuffle阶段,通过这种方式,它们可以“与众不同” 自然地。
根据您的情况,它运行缓慢,因为只有一个 减速器可处理大量详细数据。您可以使用分组方式 在获得更多并行性之前,先进行计数:
select count(1) from (select id from tbl group by id) tmp;
但是我不明白一些事情:
答案 0 :(得分:1)
我会尝试解释。
第1部分:
回答者是什么意思,“那些“由...区别”键将成为MapReduce Shuffle阶段的分区键的一部分”?您能解释一下吗? UDAF
GenericUDAFCount
具有count
和count distinct
的能力。如何实现count distinct
?
让我们以以下查询为例:
select category, count(distinct brand) from market group by category;
将为该查询启动一个MapReduce作业。
distinct-by
键是count(distinct ...
中的表达式(列),在这种情况下为brand
。
partition-by
键是用于在map
阶段为记录计算哈希码的字段。然后,此哈希值用于确定记录应转到哪个分区。通常,partition-by
键位于SQL查询的group by
部分中。在这种情况下,它是category
。
映射器的实际output-key
将由partition-by
键和distinct-by
键组成。对于上述情况,映射器的输出键可能类似于(饮料,百事可乐)。
此设计使具有相同group-by
键的所有行都属于同一减速器。
映射器输出的value
部分在这里无关紧要。
稍后,在随机播放阶段,记录将根据sort-by
键进行排序,该键与output key
相同。
然后在reduce
阶段,在每个单个化简器上,所有记录首先按类别分类,然后按品牌分类。这样就很容易获得count(distinct )
聚合的结果。每个不同的(类别,品牌)对保证只能被处理一次。每个组的聚合已变成count(*)
。调用reduce
方法的输入键将是这些不同对之一。 Reducer进程跟踪组合键。每当类别部分更改时,我们就会知道会有一个新的组,并且我们将从1开始对该组进行计数。
第2部分:
在这种情况下,为什么只有一个减速器? 在不使用
count distinct
的情况下计算group by
时:
select count(distinct brand) from market
只有一个减速器负责所有工作。为什么?因为partition-by
键不存在,或者我们可以说所有记录都具有相同的哈希码。因此它们将属于同一减速器。
第3部分:
为什么奇怪的内部查询会导致更多分区?
内部查询的partition-by
键是group by
键id
。 id
值很可能分布均匀,因此记录由许多不同的化简器处理。然后在进行内部查询之后,可以得出结论,所有id
都互不相同。因此,现在只需要一个简单的count(1)
。
但请注意,输出将仅启动一个减速器。为什么不遭受痛苦?由于count(1)
不需要详细的值,因此映射端聚合极大地减少了reducer处理的数据量。
还有一件事,由于重写会引入额外的MR阶段,因此不能保证性能会更好。