Hive面试

2020-09-18  本文已影响0人  Rinma

1.描述一下Hive的基本架构?

Hive架构.png
  1. 用户接口
    • CLI:Shell终端命令行,采用交互式方式与Hive进行交互
    • JDBC/ODBC:基于JDBC提供的客户端,常用的有beeline链接hive-server2
    • WEB UI:通过浏览器访问Hive。需要通过配置(hive-site.xml)开启,不常用。
  2. 跨语言服务
    • Thrift Server:Thrift是Facebook开发的一款扩拓展的、跨语言的服务框架。Hive可以通过此框架直接不同变成语言调用其接口。
  3. Driver
    Driver组件提供了HQL语句的语法分析、变异、优化以及生成逻辑执行计划的全部过程。逻辑执行计划最终保存在HDFS中,并随后由MapReduce调用。
    • 解释器(SQL Parser):负责将HQL语句转换为抽象语法树(AST)。
    • 编译器(Logical Plan):将抽象语法数编译为逻辑执行计划。
    • 优化器(Query Optimizer):对逻辑执行计划进行优化。
    • 执行器(Execution):调用底层运行框架执行逻辑执行计划。
  4. MapReduce
    Hive默认使用MapReduce框架执行HQL任务。
  5. HDFS
    Hive作为数据仓库,本身并不保存数据,而是将HDFS上的结构化数据映射为表。因此Hive执行的任务,本质上还是调用HDFS上的结构化数据。
  6. Meta Store
    元数据(Meta Store)本质上就是对Hive中的库、表结构以及HDFS数据位置的描述信息。通常保存在MySQL之类的关系型数据库中。
    Hive的元数据包括:库名、表名、表列、表属性、表分区、表数据位置等。
    Hive编译器在变异HQL语句时,会首先调用MetaStore元数据进行类型和语法的合法性检测。

2.HQL转换为MapReduce的过程?

  1. 用户提交HQL语句
  2. 解释器(SQL Parser)调用元数据对HQL进行类型和语法的合法性检测,并将HQL转换为抽象语法树。
  3. 语义分析器(Semantic Analyzer)遍历抽象语法树,抽出任务的基本组成单元(Query Block)。
  4. 编译器(Logical Plan)将Query Block编译为操作树(Operator Tree)。
  5. 优化器(Query Optimizer)优化操作树,合并不必要的ReduceSinkOperator,减少Shuffle数据量。
  6. 遍历优化后的操作树,生成MapReduce任务。
  7. 执行器提交MapReduce任务。

3.内部表和外部表的区别

4.谈一下Hive的特点?Hive与RDBMS的区别?

5.请说明Hive中 Order By、Sort By、Distrbute By、Cluster By各代表什么意思?

6.谈谈你对Hive窗口的理解?以及Hive是如何设置窗口大小的?
Hive的窗口函数是基于行数据的开窗,由OVER()关键字指定,通常搭配PARTITION BYORDER BY指定分区和排序字段,以及ROW BETWEEN指定窗口大小。
Hive窗口大小由ROW BETWEEN关键字指定,由PRECEDING指定当前行前,由CURRENT ROW指定当前行,由FOLLOWING指定当前行后。
如指定首行到当前行:

OVER(PARTITON BY a ORDER BY b ROW BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

指定当前行到尾行:

OVER(PARTITON BY a ORDER BY b ROW BETWEEN CURRENT AND UNBOUNDED FOLLOWING)

指定当前行前10行到后10行:

OVER(PARTITON BY a ORDER BY b ROW BETWEEN 10 PRECEDING AND 10 FOLLOWING)

7.谈谈Hive中的几个排名函数?
Hive的排名函数共有三个,分别为ROW_NUMBERRANKDENSE_RANK
ROW_NUMBER:按照排序顺序生成排名,不产生重复名次。
RANK:按照顺序生成排名,产生重复名次,重复名次会在排名中留下空位。例如1、2、2、4...
DENSE_RANK:按照顺序生成排名,产生重复名字,重复名次不会在排名中留下空位。例如1、2、2、3...

8.描述下Hive中的null是怎么存储的?
在Hive底层。null作为"\N"进行存储。
在与其他数据库做交互时,需要提前对其进行处理。如sqoop导出Hive数据到MySQL。

9.你常用的内置函数有什么?简单描述下它们的作用?
SPLIT:将字符串按照指定分隔符切分为字符串数组。如:SELECT SPLIT("a,b,c", ",")
LENGTH:返回字符创长度。
REVERSE:反转字符串。
SUBSTR:截取字符串。
ARR_CONTAINS:数组包含。
CASE:类型转换。
REGEXP_REPLACE:正则替换。
PARSE_URL/PARSE_URL_TUPLE:url解析函数。
GET_JSON_OBJECT:Json解析函数。
...

10.除了上面的几个排名函数,你还用过什么窗口函数?

LAG(age, 5, 18) OVER(PARTITION BY name ORDER BY name)
LEAD(age, 10, 19) OVER(PARTITION BY name ORDER BY name)
FIRST_VALUE(age) OVER(PARTITION BY name ORDER BY name)
LAST_VALUE(age) OVER(PARTITION BY name ORDER BY name)

11.列举下你所知道的列转行函数?

12.列举下你所知道的行专列函数?

LATERAL VIEW() EXPLODE(SPLIT(a)) tableAlias AS columnAlias

13.COLLECT_LIST()COLLECT_SET() 函数有什么区别?
相同点:COLLECT_LIST()COLLECT_SET()两个函数,都是将一个列转换为一个数组,并返回。
区别:COLLECT_LIST()转换后的数组为全部数据,不进行去重;COLLECT_SET()转后的数组为去重后的数据。

14.UDF、UDAF、UDTF的区别?你有写过类似的代码吗?

15.谈谈你在使用Hive过程中经常遇到的几类问题?

  1. 数据倾斜导致的OOM。
  2. 数据倾斜导致的任务执行时间过长。
  3. ORDER BY导致的任务执行时间过长。

16.Hive数据倾斜的原因有哪些?并请举例一下具体的处理方法?
数据倾斜是指:由于数据分布不均匀,造成数据大量集中在某个或者某几个key上,从而导致的任务执行数据过慢,甚至OOM的情况。
产生数据倾斜的原因:

  1. 使用DISTINCT col导致的数据倾斜问题。
    因为在使用DISTINCT进行去重操作时,Hive会默认只启用一个Reduce进行去重,因此会导致任务指定速度过长,甚至产生OOM。
    解决方案:此时可以使用GROUP BY代替DISTINCT进行去重操作,GROUP BY会根据key的数量动态或手动指定生成N个Reduce,可以大幅缓解数据倾斜的问题。
    GROUP BY去重:
SELECT a FROM b GROUP BY a;

GROUP BY去重统计:

SELECT COUNT(1) cnt FROM (SELECT a FROM b GROUP BY a);
  1. 空值产生的数据倾斜问题
    在数据中,常会出现某值大量为NULL的情况,此时如果按照该值进行join操作时,就会出现数据倾斜的问题。
    解决方案1:过滤该NULL值,如果业务本身不关心NULL值,则直接丢弃;否则,在join完成后,union该NULL值。
SELECT
      b.userid uderid, a.classname classname, b.username username
FROM
      a
INNER JOIN
      (SELECT userid, username FROM b WHERE userid IS NOT NULL) b
ON
      a.userid = b.userid
UNION ALL
SELECT
      userid, null, username
FROM
      b
WHERE
      userid IS NULL;

解决方案2:为NULL值赋予随机值。这种做法可以使得NULL值不被shuffle到一起,从而避免数据倾斜的产生。

SELECT
    CASE
        WHEN a.userid LIKE 'hive%' THEN NULL
        ELSE a.userid
    END userid, b.classname classname, c.username username
FROM
    a
LEFT JOIN
    b
ON
    CASE
        WHEN a.userid IS NULL THEN CONNCAT("hive_", RAND())
        ELSE a.userid
    END = b.userid

3.大小表关联产生的数据倾斜问题。
大小表JOIN产生数据倾斜的时候,可以启用MAP JOIN将小表直接分发出去(类似Spark和Flink里的broadcast),这样小表数据将存储在每个Executor上,在JOIN的时候不会产生reduceTask,因此也就不会发生数据倾斜的问题了。

SELECT /* + MAPJOIN(a) */ a.userid, b.username FROM a INNER JOIN b ON a.userid = b.userid;

在Hive 0.11版本后,MapJoin是默认开启的,这个优化策略将有Hive自动执行。由以下两个参数控制:

SET hive.auto.convert.join=true;  // 开启MapJoin自动优化
SET hive.mapjoin.smalltable.size=25000000;  // 当小表超过该大小时,MapJoin将自动失效。生产环境中,如果内存赋予,可以扩大该参数值。
  1. 大表与大表关联产生的数据倾斜问题。
    解决方案1: 这种情况下,如果是因为NULL值产生的数据倾斜,且业务场景对NULL值并不关心,则可以提前将NULL过滤,如此可以避免数据倾斜的发送;如果NULL值过多,也可能回归到大小表JOIN的优化上去。
    解决方案2:如果业务场景对NULL值有需求,那么此时可以参照"2. 空值产生的数据倾斜问题"的解决方案2,为NULL值赋予随机值,并在任务最后将随机值还原为NULL值;或者解决方案1,将NULL过滤,在后续通过UNION ALL将数据合并。此方案同样适用于单个key数据量过大产生的数据倾斜问题。
    解决方案3:如果业务场景是因为热点数据(多个key值数据量特大)问题产生的数据倾斜,因为数据量大的key值过多,此时不再适用于解决方案2,此时可以对所有key都打上一个随机值,此时将不再根据原key进行shuffle,hash结果为key_rand,将会打乱原key进行新的hash分组。在最后再将结果中的rand去除进行二次JOIN。
  2. 预聚合优化
    这种优化多用在GROUP BY产生数据倾斜时,此时可以通过参数开启Hive的预聚合和负载均衡优化,此时Hive会在第一个MR Job时将输出数据随机分配到Reduce中,在每个Reduce内做预聚合,此时相同的key可能分发到不同的Reduce内,从而起到负载均衡的作用;在第二个MR Job中,Hive按照key进行分组,此时将会按照key的hash进行分组,从而保证结果的正确性。
SET hive.map.aggr=true;  // 开启预聚合
SET hive.groupby.skewindata=true;  // 开启数据倾斜负载均衡
  1. 并发度优化
    数据倾斜的问题,最终还是因为某些key数据量过大而造成的数据热点问题。因此在资源充足的情况下,尽可能的在合理的范围内扩大Reduce的数量和任务资源占有量,可以达到缓解数据倾斜的问题。

17.平时针对Hive做了什么优化?

  1. 建模。合适的建模会减少很多优化的工作量。
  2. 解决数据倾斜问题。针对不同的数据,选择不同的数据倾斜解决方案。
  3. 减少MR Job数量。对于MR任务来说,Job的启动和销毁很重,因此减少Job数量会极大提高任务运行效率。
  4. 设置合理的Map和Reduce数量。Map和Reduce数量的提高虽然会缓解数据倾斜的问题,但是也会带来任务执行效率的降低,因此合适的Map、Reduce数量将会加快任务的执行效率。
  5. 充分利用Hive的特性来对任务做优化。例如Hive存储多会使用Parquet等列存储方式,因此在符合业务场景的情况下,避免使用*的匹配查询,而选择单列的查询。
  6. 尽量减少任务读取的数据量,合理利用分区的特性。多使用WHERE对数据进行过滤,可以有效提高任务执行效率。
  7. 使用多表关联时,尽可能利用Map Join的特性。例如小表在左,因为Hive会优先尝试加载左表到内存。
  8. 避免使用低效率的函数。部分Hive函数会将Reduce数量限制为1,在不影响业务的情况下,尽可能避免使用之类函数。例如DISTINCTORDER BY
  9. 合并小文件。Hive在读取文件阶段,每个Block块都会生成一个Map任务,而且小文件对HDFS影响居多,因此尽可能的使HDFS内的文件大小接近128M或者接近128M的倍数(128M为默认的HDFS块大小,如果有自定义块大小,需根据实际情况调整)。
  10. HQL并不是语句越复杂越好,如果有相同需求的情况下,尽可能利用临时表或者View来对公共中间数据做重复利用。
  11. 尽量不输出全量数据,而是使用LIMIT或者ROW_NUMBER等函数进行截取。

18.谈谈Hive的分桶表?以及使用场景?
分桶表不同于分区表。分区在物理表现形式上为HDFS中的子目录,而分桶则是利用hash的特性(字段hash值 % 分桶个数)将数据落在不同的文件内。
因为对指定字段做了hash,并将其做了归类,因此在抽样查询和Join操作(需要Join的字段为分区字段)时,会极大提高读取效率。
但是分桶表会加重数据加载的负担,降低数据入库的效率,而且在普通的数据分析任务中无法起到提高效率的能力,因此仅在部分特殊环境下使用。在实际环境中,需酌情考虑。
分桶表常用在需要数据抽样的环境中(我未在实际生产环境中使用过分桶表,猜测可能会对机器学习或者深度学习的环境中起到作用)。

19.Hive map,reduce数怎么设置?怎么优化?

SET mapred.max.split.size=256000000;  // 每个Map任务所能接收数据的最大值。
SET mapred.min.split.size=100000000;  // 每个Map任务接收数据的最小值。
SET mapred.min.split.size.per.node=100000000;  // 一个节点上Split的最小值。
SET mapred.min.split.size.per.rack=100000000;  // 一个交换机环境下Split的最小值。
SET set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;  // 对小文件进行聚合。
SET hive.exec.reducers.bytes.per.reducer=1000000000;// 每个Reduce所能承载的数据的最大值。默认为1G。
SET hive.exec.reducers.max=999;  // 每个Job中所能产生的Reduce的最大值。默认为999。
SET mapred.reduce.tasks=10;  // 设定Job所产生的Reduce的具体数量。
  1. 合并输入文件
SET mapred.max.split.size=256000000;  #每个Map最大输入大小
SET mapred.min.split.size.per.node=100000000; #一个节点上split的至少的大小
SET mapred.min.split.size.per.rack=100000000; #一个交换机下split的至少的大小
SET hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;  #执行Map前进行小文件合并
  1. 合并输出文件
SET hive.merge.mapfiles = true #在Map-only的任务结束时合并小文件
SET hive.merge.mapredfiles = true #在Map-Reduce的任务结束时合并小文件
SET hive.merge.size.per.task = 256*1000*1000 #合并文件的大小
SET hive.merge.smallfiles.avgsize=16000000 #当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge。
SET hive.exec.compress.intermediate=true;  // 开启中间结果压缩
SET hive.intermediate.compression.codec="org.apache.hadoop.io.compress.LzoCodec";  // 设定压缩格式为LZO。

20.Hive的存储格式有哪些?你之前选择了什么存储格式?为什么?

21.Hive文件压缩格式有哪些,压缩效率如何?
Hive的文件压缩格式,实际上就是HDFS的压缩格式。
HDFS压缩格式通常有五种:gzip、bzip2、snappy、lzo以及HDFS默认的压缩格式(不常用不做讲解)。

压缩特性.png
压缩性能.png
数据来自于:https://blog.csdn.net/zhouyan8603/article/details/82954459

22.join操作底层的MapReduce是怎么去执行的?
Hive的join操作分为两种:MapJoin和ReduceJoin。

23.你知道Hive中有几种去重方式?列出它们的优点和缺点?

  1. DISTINCT:用法灵活,可以在一条HQL同时对多个字段进行单独去重;但是在海量数据中会发生数据倾斜的问题。
  2. GROUOP BY:对海量数据有很好的支撑能力;但是对多个字段单独去重较为复杂,需要多个子查询支撑。
上一篇 下一篇

猜你喜欢

热点阅读