函数
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_durationfrom (select key_day,device_id,sum(play_duration) as sum_duration,rank() over (partition by key_day order by sum(play_duration) desc) as rankfrom test.video_playwhere 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操作可能会发生数据倾斜?
对照上面的表格,可以得出有三种情况可能会发生数据倾斜:
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_datafrom calendar_record_logwhere 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_datafrom calendar_record_logwhere day_p between '20190101' and '20190131'distribute by uidsort 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则为开启严格模式。