开发实战角度:distinct实现原理及具体优化总结

如题所述

Distinct是一种在数据库SQL语言中至关重要的操作,尤其在Hive中,它通过MapReduce机制来实现。Distinct操作可以应用于单列或多列,其基本原理是对数据集按照指定列进行分组,去除每个分组内的重复值,最终合并成唯一值的结果集。

在最近的一次学习过程中,有位伙伴在研究count distinct时遇到了难题。虽然对单个count distinct原理理解尚可,但面对多字段count distinct时,讲解起来就变得复杂。下面将为大家总结这方面的内容。

在深入Distinct之前,先来了解一下group by操作的实现原理。group by操作适合与distinct紧密相关的聚合操作,因此,总结distinct之前,需要了解group by的具体实现。

在map阶段,将group by后的字段组合作为key,如果是单个字段,则key为一个。group by之后要进行的聚合操作字段作为值,如count则值为1;若sum另一个字段,则value是该字段值。shuffle阶段,按照key的不同分发到不同的reducer。reduce阶段,如果是count则将相同key的值累加,如果是其他操作,则按需要的聚合操作得到结果。

在map阶段如果出现数据倾斜,可以进行相应的处理,常见的方法有单独计算key、替换随机数等。针对group by的特殊方法有几种。

Distinct单字段原理:当执行Distinct操作时,Hive将其转化为MapReduce作业,并按指定列进行分组。Map阶段,每个Mapper读取输入数据,将指定列作为输出的key,通过Shuffle过程将具有相同key的数据发送到同一个Reducer中。由于使用了distinct,Map端的combine无法合并重复数据,因此必须将id作为Key输出,在Reduce阶段再进行消重。

对于count(distinct)全聚合操作,即使设置了reduce task的具体个数,Hive最终也只会启动一个reducer。这导致所有map端传来的数据都在一个tasks中执行,唯一的Reduce Task需要处理大量的数据,这成为整个作业的IO和运算瓶颈。

Distinct一个字段时,将group by的字段和distinct的字段组合作为map输出的key,value设置为1,同时将group by的字段定为分区键。这样就可以将GroupBy字段作为reduce的key,在reduce阶段利用mapreduce的排序,输入天然就是按照组合key排好序的。根据分区键将记录分发到reduce端后,按顺序取出组合键中的distinct字段,这时distinct字段也是排好序的。依次遍历distinct字段,每找到一个不同值,计数器就自增1,即可得到count distinct结果。

对于单distinct的优化,可以通过将原来一个MapReduce作业转换为两个作业,在第一阶段选出全部的非重复的字段id,在第二阶段再对这些已消重的id进行计数。这样可以在第一阶段通过增大Reduce的并发数来处理Map输出,在第二阶段,由于id已经消重,COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。

对于mult-distinct,如果按照上面一个distinct字段的方法,无法根据uid和date分别排序,也就无法通过LastKey去重,仍然需要在reduce阶段在内存中通过Hash去重。Hive会使用另一种处理方式,对所有的distinct字段编号,那么相同字段就会分别排序,这时只需要在reduce阶段记录LastKey即可去重。这种实现方式利用了MapReduce的排序,节省了reduce阶段去重的内存消耗,但缺点是增加了shuffle的数据量。

对于多重distinct的操作,可以按照一定步骤进行优化。
温馨提示:答案为网友推荐,仅供参考

相关了解……

你可能感兴趣的内容

大家正在搜

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网