美文网首页
Hive面试

Hive面试

作者: Rinma | 来源:发表于2020-09-18 00:03 被阅读0次

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.内部表和外部表的区别

  • 内部表(Managed Table),又称管理表。当用户删除内部表时,HDFS存储的数据会随之被删除。
  • 外部表(Ex't'ranal Table)。用户建立表时,需要通过LOCATION关键字指定数据保存位置;删除表时,HDFS数据不会被删除,只会删除元数据中的表信息。

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

  • Hive的特点
    • Hive并不存储数据,而是将HDFS上的结构化数据映射为表结构,其元数据可以保存在其他关系型数据库中。
    • Hive不支持行级别的增删操作,如果需要进行更新,只能通过分区或者覆盖的方式进行更新。
    • Hive默认使用MapReduce作为底层调度引擎,因此任务执行延迟较高。在小数据量情况下,关系型数据库执行效率远超Hive,只有在海量数据情况下,Hive的并行化计算优势才能体现。
    • Hive可以将HQL转换为MapReduce任务进行数据分析,简化了MapReduce的学习成本。
    • Hive任务执行延迟高,因此不支持实时计算。
    • Hive是基于Hadoop之上构建的,因此Hive可以跟随Hadoop进行水平扩展。在水平拓展时,只需要部署Hive环境,并将现有配置文件分发到该节点即可。
  • Hive与RDBMS的区别
    Hive与RDBMS的区别.png
    图片来源于:https://www.cnblogs.com/qingyunzong/p/8707885.html

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

  • Order By:会对输出做全局排序,因此只会生成一个Reduce。如果最终输出结果较大,一个Reduce会导致任务的执行延迟变高。
  • Sort By:在每个Reduce内部做排序,而非全局排序。因此输出数据不是全局有序。通常与Distrbute By结合使用。
  • Distrbute By:按照指定的字段,将数据划分到不同的Reduce中去。通常与Sort By结合使用。
  • Cluster By:CLUSTER BY a等同于DISTRBUTE BY a SORT BY a

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:用于统计当前行向前的第N行数据。用法LAG(col, n, default),col为列名,n表示第几行,default为默认值。
LAG(age, 5, 18) OVER(PARTITION BY name ORDER BY name)
  • LEAD:与LAG相反,用于统计当前行向后的第N行数据。用法LEAD(col, n, default),col为列名,n表示第几行,default为默认值。
LEAD(age, 10, 19) OVER(PARTITION BY name ORDER BY name)
  • FIRST_VALUE:分组排序后,取其第一个值。用法FIRST_VALUE(col),col为列名。
FIRST_VALUE(age) OVER(PARTITION BY name ORDER BY name)
  • LAST_VALUE:分组排序后,取其截至到当前行的最后一个值。用法LAST_VALUE(col),col为列名。
LAST_VALUE(age) OVER(PARTITION BY name ORDER BY name)

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

  • CONCAT(str1, separator1, str2, separator2, str3...):将指定字符串按照指定分隔符进行拼接,分隔符只需要指定多次。
  • CONCAT_WS(separator, str1, str2...):将指定字符串按照指定分隔符进行拼接,分隔符只需要指定一次。
  • COLLECT_LIST(col):将指定列转换为不去重的数组。
  • COLLECT_SET(col):将指定列转换为去重的数组。

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

  • EXPLODE(col):将Hive中类型为复杂类型Array或者HashMap的列转换为多行。
  • LATERAL VIEW():常与UDTF函数配合使用,将指定列拆分为多行数据。
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的区别?你有写过类似的代码吗?

  • UDF(User Defined Function):用户自定义函数,数据为单进单出。需要继承UDF类,并重写evaluate方法。
  • UDAF(User Defined Aggregation Function):用户自定义聚合函数,数据为多进单出。需要继承UDAF类,并重写inititerateterminatePartialmergeterminate方法。
  • UDTF(User Defined Table-Generating Function):用户自定义表生成函数,数据为单进多出。需要继承GenericUDT类,并重写initialize, process, close方法。

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

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

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

  • Key分布不均匀
  • 业务数据本身的特性
  • 建表时考虑不周
  • 数据内存在大量NULL值
  • 某些HQL本身就存在数据倾斜
  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数怎么设置?怎么优化?

  • Map:一般来说,MR的Map数量多保持为由任务自动分配,但是如果HDFS环境内存在大量小文件,针对小文件做计算或者单个文件存在少量字段大量数据时,推荐自定义Map任务数量。
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;  // 对小文件进行聚合。
  • Reduce:Reduce的数量过多,会导致每个Reduce上处理的数据量过少,任务效率会被Reduce任务的初始化和销毁过程严重降低;Reduce的数量过少,可能会出现数据倾斜的问题。因此Reduce数量是实际生产环境中最常也是最难调优的。
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。
  • 对中间文件进行压缩
    MR任务在指定过程会产生大量的中间文件,基于MR引擎的Hive也不例外。
    如果在实际业务场景中,处理的数据量庞大,但是CPU资源富余,可以采用将中间结果压缩的方式,来减轻shuffle的压力。
SET hive.exec.compress.intermediate=true;  // 开启中间结果压缩
SET hive.intermediate.compression.codec="org.apache.hadoop.io.compress.LzoCodec";  // 设定压缩格式为LZO。

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

  • TextFile
    Hive的默认存储方式。文本存储、行存储、不支持块压缩,磁盘开销大、数据解析开销大,不建议生产环境使用。
  • SequenceFile
    HDFS提供的二进制文件格式。行存储,可压缩、可分割、可切片。
  • RCFile
    早期的行列存储方式,支持压缩和快速的查询性能,写操作较慢,比行式存储占用更多的存储空间。
    RCFile是行、列结合的存储方式。首先将数据按行分块,块数据按列存储,避免了一条记录的多Block读取,并且列存储的方式有利于数据的压缩和快速的列读取。
  • ORCFile
    RCFile的升级版,同样是按行分块,按列存储,但是对于RCFile读取效率上有大幅提升。
  • Parquet
    Parquet是纯粹的列存储格式,有很好的压缩性能,以及快速的列读取能力。但是写入速度较慢。
    拥有很好的兼容能力(Impala、Presto等都是基于Parquet的)。
    在生产环境中,我们选择了Parquet的列存储格式,以及Snappy的压缩格式。选择Parquet是因为它是列存储,对于海量数据中针对部分列的读取有很好的性能,更重要的是,它可以完美兼容Impala和Presto。

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。

  • ReduceJoin:在Reduce阶段完整Join操作,也是一般的Join。
    在Map阶段,输出以join操作的key的键值的数据,如果join有多个条件,则以这些key作为键值。
    Reduce阶段,以这些key完成join操作。
  • MapJoin:大小表Join。
    首先将小表转换为HashTable结构,并写入本地文件中,然后将该文件加载到DistributeCache中去。该任务为Local任务。
    然后生成没有Reduce的MR任务,读取每一条数据与DistributeCache中的数据进行关联,最终生成结果。

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

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

相关文章

  • 数仓--Hive--面试题准备

    数仓--Hive-面试之Hive与HBase的区别数仓--Hive-面试之Hive架构原理数仓--Hive-面试之...

  • 面试题汇总:Hive

    1.《大数据Hive 面试以及知识点》 2.《Hive学习之路 (十一)Hive的5个面试题》 3.《大数据工程师...

  • Hive面试

    1.描述一下Hive的基本架构? 用户接口CLI:Shell终端命令行,采用交互式方式与Hive进行交互JDBC/...

  • Hive相关文章索引(2)

    环境部署 HiveServer2的高可用-HA配置 基本常识 大数据Hive 面试以及知识点 hive实现upda...

  • Hive调优

    本文种记录的大多是开源版本hive调优方式 我也会补充TDH集群Inceptor的优化方式 面试必备技能-Hive...

  • 数仓--Hive-面试之Hive动态分区

    面试如果被问道,那么需要说出彩来,特别时参数 Hive动态分区参数配置 往hive分区表中插入数据时,如果需要创建...

  • Redis、传统数据库、HBase以及Hive的区别

    在面试的时候,很多面试官都会问Redis、HBASE、Hive、数据库的区别,其实面试官考核的是你对不同数据存储技...

  • Hive和Spark当中对小文件的处理

    Hive当中对小文件的处理 数仓面试高频考点:【在Hive中如何解析小文件过多问题,指定的是:处理表中数据时,有很...

  • Hive面试题

    1. 什么是数据倾斜, 如何处理 什么是数据倾斜 大量相同的key被partition到一台机器, 造成这台机器...

  • hive面试题

    http://bigdatastudy.net/show.aspx?id=163&cid=14 https://b...

网友评论

      本文标题:Hive面试

      本文链接:https://www.haomeiwen.com/subject/dsekyktx.html