Hive之面试集锦<二>

Hive之面试集锦<二>

函数

Hive函数的考察主要是函数的使用,一般代码类的题目居多,窗口函数是考察的要点。

18.统计每天的人均播放次数和播放时长,其中播放次数按照起播日志来算,播放时长按照播放结束日志来统计

SELECT a.key_day,a.avg_play_num,b.avg_duration
(
select key_day,count(device_id)/count(distinct device_id) as avg_play_num
from test.video_play
where event = 'start' //限定为起播日志
group by key_day
) a
join
(
select key_day,sum(duration)/count(distinct device_id) as avg_duration
from test.video_play
where event = 'end' //限定为结束播放日志
group by key_day
) b
on a.key_day = b.key_day

19.找出每天播放时长最长的用户

select key_day,device_id,sum_duration
from
(select key_day,device_id,sum(play_duration) as sum_duration,rank() over (partition by key_day order by sum(play_duration) desc) as rank
from test.video_play
where event = 'end'
group by key_day,device_id
) a
where rank = 1

20.你知道哪些统计函数和窗口函数吗?

  • 统计函数有:sum、avg、max/min、count
  • 窗口函数常用的有:除了上述统计函数外,还有first_value/last_value、lag/lead、rank、row_number

21.hive中 order by,sort by,cluster by,distrbute by,partition by各代表什么意思?

  • order by:会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)。当输入规模较大时,需要较长的计算时间。
  • sort by:不是全局排序,其在数据进入reducer前完成排序。
  • distribute by:按照指定的字段对数据进行划分输出到不同的reducer中。
  • cluster by:除了具有 distribute by 的功能外还兼具 sort by 的功能。
  • partition by
    :按照指定字段进行分区,用在窗口函数中。

数据倾斜

22.什么是数据倾斜?

数据倾斜就是数据的分布不平衡,某些地方特别多,某些地方又特别少,导致在处理数据的时候,有些很快就处理完了,而有些又迟迟未能处理完,导致整体任务最终迟迟无法完成,这种现象就是数据倾斜。

23.你知道发生数据倾斜的原因吗?

发生数据倾斜的原因有很多,大致可以归为:

1)key分布不均匀;

2)数据本身的特性,原本按照日期进行分区,如果在特定日期数据量剧增,就有可能造成倾斜;

3)建表时考虑不周,分区设置不合理或者过少;

4)某些 HQL 语句本身就容易产生数据倾斜,如 join。

24.哪些HQL操作可能会发生数据倾斜?

Hive之面试集锦<二>

对照上面的表格,可以得出有三种情况可能会发生数据倾斜:

1)join

大小表join的时候,其中一个较小表的key集中,这样分发到某一个或者几个的Reduce上的数据就可能远高于平均值;

两张大表join的时候,如果有很多0值和空值,那么这些0值或者空值就会分到一个Reduce上进行处理;

join的时候,不同数据类型进行关联,发生类型转换的时候可能会产生null值,null值也会被分到一个Reduce上进行处理;

2)group by

进行分组的字段的值太少,造成Reduce的数量少,相应的每个Reduce的压力就大;

3)count distinct

count distinct的时候相同的值会分配到同一个Reduce上,如果存在特殊的值太多也会造成数据倾斜。

Hive优化

Hive优化包括Hive Sql优化以及Hive的配置参数优化。

25.count(distinct uid),该用法在MR 的 reduce 阶段只有一个 reduce 来处理,当数据量较大会导致严重的数据倾斜,如何进行优化呢?

可以先对uid进行去重,然后再count统计。

select count(1) from (select distinct(uid) d_uid from table) x

26.以下代码,如果数据量很大,会有什么问题?如何优化?

select uid,upload_time,event_type,record_data
from calendar_record_log
where day_p between '20190101' and '20190131'
order by upload_time desc,event_type desc;

Hive SQL中的order by就是将结果按某字段全局排序,这会导致所有map端数据都进入一个reducer中,在数据量大时可能会长时间计算不完。

可以使用sort by,会视情况启动多个reducer进行排序,并且保证每个reducer内局部有序。为了控制map端数据分配到reducer的key,往往还要配合distribute by一同使用,如果不加distribute by的话,map端数据就会随机分配到reducer。

下面是优化后的代码。

select uid,upload_time,event_type,record_data
from calendar_record_log
where day_p between '20190101' and '20190131'

distribute by uid
sort by upload_time desc,event_type desc;

27.谈谈如何对join操作进行优化?

join优化是个复杂的问题,可以从以下几点进行优化:

1)小表前置

大小表在join的时候,应该将小表放在前面,Hive在解析带join的SQL语句时,会默认将最后一个表作为大表,将前面的表作为小表并试图将它们读进内存。如果表顺序写反,大表在前面,可能会引发OOM。

2)key值相同

多表join的时候尽量使用相同的key来关联,这样会将会将多个join合并为一个MR job来处理。

3)利用map join特性

map join特别适合大小表join的情况。Hive会将大表和小表在map端直接完成join过程,消灭reduce,效率很高。Hive 0.8版本之前,需要加上map join的暗示,以显式启用map join特性,具体做法是在select语句后面增加/*+mapjoin(需要广播的较小表)*/。

map join的配置项是hive.auto.convert.join,默认值true;还可以控制map join启用的条件,hive.mapjoin.smalltable.filesize,当较小表大小小于该值就会启用map join,默认值25MB。

28.对于空值或者无意义的值引发的数据倾斜,该怎么处理呢?

这在写程序的时候要考虑清楚,这些异常值的过滤会不会影响计算结果,如果影响那就不能直接过滤掉,可以将这些异常的key用随机方式打散,例如将用户ID为null的记录随机改为负值。

29.如何调整mapper数?

mapper数量与输入文件的split数息息相关,可以通过设置相关参数来调整mapper数。

1)可以直接通过参数mapred.map.tasks(默认值2)来设定mapper数的期望值,但它不一定是最终mapper数;

2)输入文件的总大小为total_input_size。HDFS中,一个块的大小由参数dfs.block.size指定,默认值64MB或128MB。所以得出来的默认mapper数就是:

default_mapper_num = total_input_size / dfs.block.size,但是它也不一定是最终的mapper数;

3)设置参数mapred.min.split.size(默认值1B)和mapred.max.split.size(默认值64MB)分别用来指定split的最小和最大值。那么split大小和split数计算规则是:

split_size = MAX(mapred.min.split.size, MIN(mapred.max.split.size, dfs.block.size));

split_num = total_input_size / split_size。

4)最终得出mapper数:

mapper_num = MIN(split_num, MAX(default_mapper_num, mapred.map.tasks))。

其中可变的参数有:mapred.map.tasks、dfs.block.size(不会为了一个程序去修改,但是也算是一个可变参数)、mapred.min.split.size、mapred.max.split.size,通过调整他们来实现,mapper数的变化。

30.如何调整reducer数?

使用参数mapred.reduce.tasks可以直接设定reducer数量,不像mapper一样是期望值。如果不设这个参数的话,Hive就会自行推测,逻辑如下:

1)参数hive.exec.reducers.bytes.per.reducer用来设定每个reducer能够处理的最大数据量。

2)参数hive.exec.reducers.max用来设定每个job的最大reducer数量。

3)reducer数:

reducer_num = MIN(total_input_size / reducers.bytes.per.reducer, reducers.max)。

reducer数量决定了输出文件的数量。如果reducer数太多,会产生大量小文件,对HDFS造成压力。如果reducer数太少,每个reducer要处理很多数据,容易拖慢执行时间也有可能造成OOM。

31.什么时候又需要合并文件?如何合并小文件?

当有很多小文件的时候没需要合并小文件,可以在输入阶段合并,也可以在输出阶段合并。

1)输入阶段合并

要想文件自动合并,需要更改Hive的输入文件格式,通过参数hive.input.format来更改,默认值是org.apache.hadoop.hive.ql.io.HiveInputFormat,需要改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat。还需要设置mapred.min.split.size.per.node和mapred.min.split.size.per.rack这两个参数,他们的含义是单节点和单机架上的最小split大小。设置完后,如果发现有split大小小于这两个值(默认都是100MB),则会进行合并。

2)输出阶段合并

设置hive.merge.mapfiles为true可以将map-only任务的输出合并;

设置hive.merge.mapredfiles为true可以将map-reduce任务的输出合并。另外,设置hive.merge.size.smallfiles.avgsize可以指定所有输出文件大小的均值阈值,一旦低于这个阈值,就会启动一个任务来进行合并。

32.什么是严格模式?

严格模式不允许用户执行3种有风险的HiveSQL语句,一旦执行就会直接失败。这3种语句是:

1)查询分区表时不限定分区列的语句;

2)两表join产生了笛卡尔积的语句;

3)用order by来排序但没有指定limit的语句。

将参数hive.mapred.mode设为strict则为开启严格模式。


分享到:


相關文章: