跳至主要內容

31道Hive大厂高频面试题

张启忻大约 47 分钟

31道Hive大厂高频面试题

博主闭关两个多月,查阅了数百万字的大数据资料,结合自身的学习和工作经历,总结了大厂高频面试题,里面涵盖几乎所有我见到的大数据面试题目。

《大厂高频面试题系列》目前已总结4篇文章,且在持续更新中✍。文中用最直白的语言解释了Hadoop、Hive、Kafka、Flume、Spark等大数据技术和原理,细节也总结的很到位,是不可多得的大数据面试宝典,强烈建议收藏,祝大家都能拿到心仪的大厂offer🏆。下面是相关的系列文章:

文章目录

1. 介绍一下什么是Hive

Hive 是基于 Hadoop的一个数据仓库工具,可以将HDFS中的数据文件映射为一张数据库表,并提供类SQL查询功能(HQL),提供快速开发的能力。Hive本质是将SQL转换为 MapReduce的任务进行运算,从而不必开发专门的MapReduce应用,减少开发人员的学习成本,功能扩展很方便。

拓展:

hive存的是和hdfs的映射关系,hive是逻辑上的数据仓库,实际操作的都是hdfs上的文件,HQL就是用sql语法来写的mr程序

2. Hive的架构原理

需要对 Hive 的架构有个大致的印象:

image-20210704173203053
image-20210704173203053
  • 用户接口Client:Hive可以通过CLI(Command-line Interface,即命令行),JDBC/ODBC( jdbc 访问 hive)、WEBUI(浏览器访问 hive)。

  • 元数据Metastore:Hive的元数据保存在数据库中,如保存在MySQL,SQLServer,PostgreSQL,Oracle及Derby等数据库中(默认是derby)。Hive中的元数据信息包含表名、表所属的数据库(默认是 default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。(其实就是sql表与hdfs文件之间的映射Path)

  • 驱动器Driver

    • 解析器(SQL Parser):将 SQL 字符串转换成抽象语法树 AST,这一步一般都用第三方工具库完成,比如 antlr;Antlr定义SQL的语法规则,完成SQL词法、语法解析,将SQL转化为抽象语法树AST Tree
    • 编译器(Physical Plan):将 AST 编译生成逻辑执行计划。
    • 优化器(Query Optimizer):对逻辑执行计划进行优化。
    • 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于 Hive 来说,就是 MR/Spark。

Hive 通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的 Driver,结合元数据(MetaStore),将这些指令翻译成 MapReduce,提交到 Hadoop 中执行,最后,将执行返回的结果输出到用户交互接口。

拓展:

这里有有个易混淆点,Hive 元数据默认存储在 derby 数据库,不支持多客户端访问,所以将元数据存储在 MySQL 等数据库,支持多客户端访问。

3. HiveSQL转换为MapReduce的过程

HiveSQL ->AST(抽象语法树) -> QB(查询块) ->OperatorTree(操作树)->优化后的操作树->mapreduce任务树->优化后的mapreduce任务树

img
img

过程描述如下:

  • SQL Parser(SQL解析器):Antlr定义SQL的语法规则,完成SQL词法、语法解析,将SQL转化为抽象语法树AST Tree;
  • Semantic Analyzer(语义分析):遍历AST Tree,抽象出查询的基本组成单元QueryBlock;
  • Logical plan(逻辑执行计划):遍历QueryBlock,翻译为执行操作树OperatorTree;
  • Logical plan optimizer(逻辑优化器): 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量;
  • Physical plan(物理执行计划):遍历OperatorTree,翻译为MapReduce任务;
  • Physical plan optimizer(物理优化器):物理层优化器进行MapReduce任务的变换,生成最终的执行计划。

4. hive和传统数据库之间的区别

img
img

ANSI SQL指标准化SQL

5. HiveSQL语句不会转化为MapReduce作业的情况

Fetch 抓取是指, Hive 中对某些情况的查询可以不必使用 MapReduce 计算。例如: SELECT * FROM employees;在这种情况下, Hive 可以简单地读取 employee 对应的存储目录下的文件,然后输出查询结果到控制台。

hive-default.xml.template 文件中 hive.fetch.task.conversion 默认是 more,老版本 hive
默认是 minimal,该属性修改为 more 以后,在全局查找、字段查找、limit 查找等都不走mapreduce。

案例

把 hive.fetch.task.conversion 设置成 more, 然后执行查询语句, 如下查询方式都不会执行 mapreduce 程序。

hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

把 hive.fetch.task.conversion 设置成 none,然后执行查询语句,都会执行 mapreduce程序。

hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

6. 请简单介绍一下Hive的本地模式

大多数的 Hadoop Job 是需要 Hadoop 提供的完整的可扩展性来处理大数据集的。不过,有时 Hive 的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际 job 的执行时间要多的多。对于大多数这种情况, Hive 可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。

用户可以通过设置 hive.exec.mode.local.auto 的值为 true(该值默认为false),来让 Hive 在适当的时候自动启动这个优化。

set hive.exec.mode.local.auto=true;   //开启本地 mr
//设置 local mr 的最大输入数据量,当输入数据量小于这个值时采用 local   mr 的方式,默认134217728,即 128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置 local mr 的最大输入文件个数,当输入文件个数小于这个值时采用 local mr 的方式,默
认为 4
set hive.exec.mode.local.auto.input.files.max=10;

7. 你使用过哪些 Hive 函数

(1)普通函数

图片
图片

(2)行转列函数和列转行函数

见第8题

(3)窗口函数

见第9题

8. 列转行和行转列函数有哪些

(1)行转列:把多行转成一列(多行变一行)

  • CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串,如果concat中任意字符串为null,则整个函数的返回结果为null。
  • CONCAT_WS(separator, str1, str2,...):一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间。
    注意:CONCAT_WS must be "string or array<string>即concat_ws中的参数一定是字符串或字符串数组
  • COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生 Array 类型字段。
  • collect_list(col)将所有将结果放入,不去重,返回Array类型字段

(2)列转行:把一列转成多行

  • EXPLODE(col):将 hive 一列中复杂的 Array 或者 Map 结构拆分成多行。

  • LATERAL VIEW:形成一张侧写表,它可以将原本的字段做一个关联。常和 split、explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。用法:

    #注意:as不能省略
    LATERAL VIEW udtf(expression) tableAlias AS columnAlias
    - 这个tableAias是侧写表的别名,里面只有colimnAlias这一个字段,注意:如果炸裂成两个列,则colimnAlias写两个别名
    

9. 介绍一下Hive中的窗口函数

窗口函数的语法

window_function_name(expression) 
    OVER (
       [partition_defintion]
        [order_definition]
       [frame_definition]
    )

首先需要指定窗口函数的函数名,也就是在上个例子中用的sum(),之后的OVER子句中即使没有内容,括号也需要保留,窗口由partition_defintion,order_definition,frame_definition确定,任何一个都不是必须的。

(1)partition_defintio 窗口分区

PARTITION BY expr [, expr] ...

根据表达式的计算结果来进行分区(列名也是一种表达式)。

(2)order_definition 窗口排序

ORDER BY expr [ASC|DESC] [, expr [ASC|DESC]] ...

为分区内的行的排列顺序。

(3)frame_definition 窗口框架

frame_clause:
    frame_units frame_extentframe_units:
    {ROWS | RANGE}frame_extent:
    {frame_start | frame_between}frame_between:
    BETWEEN frame_start AND frame_endframe_start, frame_end: {
    CURRENT ROW
  | UNBOUNDED PRECEDING
  | UNBOUNDED FOLLOWING
  | expr PRECEDING
  | expr FOLLOWING}

解释:

  • PRECEDING:往前
  • FOLLOWING:往后
  • CURRENT ROW:当前行
  • UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点
  • UNBOUNDED FOLLOWING:表示到后面的终点

窗口框架的作用对分区进一步细分,frame_unit有两种,分别是ROWS和RANGE,ROWS通过指定当前行之前或之后的固定数目的行来限制分区中的行,RANGE按照排序列的当前值,根据相同值来确定分区中的行。

10. Hive内部表、外部表、分区表、分桶表的区别,以及各自的使用场景

  • 内部表

如果Hive中没有特别指定,则默认创建的表都是管理表,也称内部表。由Hive负责管理表中的数据,管理表不共享数据。删除管理表时,会删除管理表中的数据和元数据信息。

绝大多数表都是外部表; 只有自己使用的临时表,才是内部表。

  • 外部表

当一份数据需要被共享时,可以创建一个外部表指向这份数据。外部表数据由HDFS管理。删除该表并不会删除掉原始数据,删除的是表的元数据。当表结构或者分区数发生变化时,需要进行一步修复的操作。

场景

每天将收集到的网站日志定期流入 HDFS 文本文件。在外部表(原始日志表)的基础上做大量的统计分析,用到的中间表、结果表使用内部表存储,数据通过 SELECT+INSERT 进入内部表。

  • 分区表

分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。 Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。

分区表使用的是表外字段,需要指定字段类型,并通过关键字partitioned by(partition_name string)声名。

  • 分桶表

分桶使用的是表内字段,已经知道字段类型,不需要再指定。通过关键字 clustered by(column_name) into n buckets声明。分桶是更细粒度的划分、管理数据,可以对表进行先分区再分桶的划分策略

分桶最大的优势就是:用于数据取样,可以起到优化加速的作用。

# 抽样查询
select * from stu_buck tablesample(bucket 1 out of 4 on 
id);

分桶规则: Hive 的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。

经测试,如果设置reduce数量n>分桶表的通数m,测mapreduce会分出分m 和 (n-m)两部分 reduce task执行,其中(n-m)个reduce task应该执行的是空任务,m个reduce task执行分桶任务。如果n<m,则执行会报错。而当educe数量设置为-1后,分桶表分几个同,则有几个reduce。

11. Order By、Sort By、Distrbute By、Cluster By的区别

  • Order By(全局排序)

order by 会对输入做全局排序,因此只有一个reduce,也正因为只有一个 reducer,所以当输入的数据规模较大时,会导致计算的时间较长。(无论设置的reduce数量为多少,都只会有一个Reducer起作用,这样才能保证全局有序)

如果在HADOOP上进行order by全排序,会导致所有的数据集中在一台reducer节点上,然后进行排序,这样很可能会超过单个节点的磁盘和内存存储能力导致任务失败。

  • Sort By(分区的排序,即每个reducer有序)

Sort by 为每个 reducer 产生一个排序文件。每个 Reducer 内部进行排序,对全局结果集来说不是排序。

  • Distrbute By(控制进入分区)

在有些情况下,我们需要控制某个特定行应该到哪个 reducer ,通常是为了进行后续的聚集操作。distribute by 子句可以做这件事。distribute by类似 MR 中 partition(自定义分区),进行分区,结合 sort by 使用。

distribute by 的分区规则是根据分区字段的 hash 码与 reduce 的个数进行模除后,余数相同的分到一个区。

  • Cluster By

当 distribute by 和 sorts by字段相同时,可以使用 cluster by 方式代替。cluster by除了具有 distribute by 的功能外还兼具 sort by 的功能。但是排序只能是 升序 排序,不能像distribute by 一样去指定排序的规则为 ASC 或者 DESC

12. 动态分区和静态分区的区别及使用场景

关于动态分区在实际生产环境中的使用也是比较的多,所以这道题出现的频率也很高,但是不难。

  • 静态分区:

定义:对于静态分区,从字面就可以理解:表的分区数量和分区值是固定的。静态分区需要手动指定,列是在编译时期通过用户传递来决定的。

应用场景:需要提前知道所有分区。适用于分区定义得早且数量少的用例,不适用于生产。

  • 动态分区:

定义:是基于查询参数的位置去推断分区的名称,只有在 SQL 执行时才能确定,会根据数据自动的创建新的分区。

应用场景:有很多分区,无法提前预估新分区,动态分区是合适的,一般用于生产环境。

具体可参考Hive动态分区多种插入方式总结open in new window

13. Hive SQL语句的执行顺序

sql语句的执行顺序from-where-group by-having -select-order by -limit

(7)    SELECT
(8)    DISTINCT <select_list>
(1)    FROM <left_table>
(3)    <join_type> JOIN <right_table>
(2)    ON <join_condition>
(4)    WHERE <where_condition>
(5)    GROUP BY <group_by_list>
(6)    HAVING <having_condition>
(9)    ORDER BY <order_by_condition>
(10)   LIMIT <limit_number>

14. 请说明一下on和where的区别

on是在生成连接表的起作用的,where是生成连接表之后对连接表再进行过滤。

当使用left join时,无论on的条件是否满足,都会返回左表的所有记录,对于满足的条件的记录,两个表对应的记录会连接起来,对于不满足条件的记录,那右表字段全部是null。

当使用right join时,类似,只不过是全部返回右表的所有记录

当使用inner join时,功能与where完全相同

注意:where虽然也可用于两个表连接,但是如果这样的话,由于on没有连接条件,会产生笛卡尔积,因此一般将where用于on连接表之后再进行过滤。

另外,不得不提的是,将 hive.strict.checks.cartesian.product 设置为 true 时, 会限制笛卡尔积的查询。 对关系型数据库非常了解的用户可能期望在 执行 JOIN 查询的时候不使用 ON 语句而是使用 where 语句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸的是, Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。

15. 请你说明hql所有的优化方式

(1)小表大表 Join(MapJOIN)/相同的key过多/表连接时引发的数据倾斜

将 key 相对分散,并且数据量小的表放在 join 的左边,可以使用 map join 让小的维度表先进内存。在 map 端完成 join。

在Hive 0.11版本之前,如果想在Map阶段完成join操作,必须使用MAPJOIN来标记显示地启动该优化操作,由于其需要将小表加载进内存所以要注意小表的大小

如将a表放到Map端内存中执行,在Hive 0.11版本之前需要这样写:

select /* +mapjoin(a) */ a.id , a.name, b.age 
from a join b 
on a.id = b.id;

如果想将多个表放到Map端内存中,只需在mapjoin()中写多个表名称即可,用逗号分隔,如将a表和c表放到Map端内存中,则 /* +mapjoin(a,c) */

在Hive 0.11版本及之后,Hive默认启动该优化,也就是不在需要显示的使用MAPJOIN标记,其会在必要的时候触发该优化操作将普通JOIN转换成MapJoin,可以通过以下两个属性来设置该优化的触发时机:

hive.auto.convert.join=true 默认值为true,自动开启MAPJOIN优化。

hive.mapjoin.smalltable.filesize=2500000 默认值为2500000(25M),通过配置该属性来确定使用该优化的表的大小,如果表的大小小于此值就会被加载进内存中。

(2)大表 Join 大表/空值引发的数据倾斜

注意:空值处理时,在非inner join的时候用,在inner join时在自动进行空值过滤。

有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key。

异常数据时,空KEY过滤

很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空,

insert overwrite table jointable select n.* from (select 
* from nullidtable where id is not null) n left join bigtable o on n.id = 
o.id;

非异常数据时,空key转换

有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。由于null 值关联不上,处理后并不影响最终结果。

set mapreduce.job.reduces = 5;

insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on 
nvl(n.id,rand()) = o.id;

(3)Group By

默认情况下, Map 阶段同一 Key 数据分发给一个 reduce,当一个 key 数据过大时就倾斜了。

两个参数:

  • hive.map.aggr=true:在map中会做部分聚集操作,效率更高但需要更多的内存。
  • hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

由上面可以看出起到至关重要的作用的其实是第二个参数的设置,它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上,所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜。

(4) Count(Distinct) 去重统计

数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题

(5)笛卡尔积

尽量避免笛卡尔积, join 的时候不加 on 条件,或者无效的 on 条件(比如1=1),比如产生大量数据

(6)行列过滤

列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用SELECT *

行处理:当join时,尽量使用谓词下推技术。

通过执行计划(explain)查看,下面两个hql的执行计划是一样的,其中,第一个hql用到了系统的谓词下推优化技术,即当join的连接字段和where后面的条件字段都是一个字段时,Hive在执行时会先根据where后面的过滤条件过滤两个表,然后再进行join。但是,当写的sql比较长时,谓词下推可能会失效。

先关联两张表,再用 where 条件过滤

hive (default)> select o.id from bigtable b
join bigtable o on o.id = b.id
where o.id <= 10;

通过子查询后,再关联表(如果join的连接字段和where后面的条件字段不是一个字段时,可以这样做)

select b.id from bigtable b
join (select id from bigtable where id <= 10) o on b.id = o.id;

(7)分区

(8)分桶

16. 解决hive小文件过多问题

参考:https://mp.weixin.qq.com/s?__biz=Mzg2MzU2MDYzOA==&mid=2247483683&idx=1&sn=14b25010032bdf0d375080e48de36d7f&scene=21#wechat_redirect

(1) 小文件产生原因

hive 中的小文件肯定是向 hive 表中导入数据时产生,所以先看下向 hive 中导入数据的几种方式

  1. 直接向表中插入数据

    insert into table A values (1,'zhangsan',88),(2,'lisi',61);
    

    这种方式每次插入时都会产生一个文件,多次插入少量数据就会出现多个小文件,但是这种方式生产环境很少使用,可以说基本没有使用的

  2. 通过load方式加载数据

    load data local inpath '/export/score.csv' overwrite into table A  -- 导入文件
    
    load data local inpath '/export/score' overwrite into table A   -- 导入文件夹
    

    使用 load 方式可以导入文件或文件夹,当导入一个文件时,hive表就有一个文件,当导入文件夹时,hive表的文件数量为文件夹下所有文件的数量

  3. 通过查询方式加载数据

    insert overwrite table A  select s_id,c_name,s_score from B;
    

    这种方式是生产环境中常用的,也是最容易产生小文件的方式。
    insert 导入数据时会启动 MR 任务,MR中 reduce 有多少个就输出多少个文件。
    所以, 文件数量=ReduceTask数量*分区数

    也有很多简单任务没有reduce,只有map阶段,则

    文件数量=MapTask数量*分区数

    每执行一次 insert 时hive中至少产生一个文件,因为 insert 导入时至少会有一个MapTask。
    像有的业务需要每10分钟就要把数据同步到 hive 中,这样产生的文件就会很多。

(2)小文件过多产生的影响

HDFS 上每个文件都要在 NameNode 上创建对应的元数据,这个元数据的大小约为150byte,这样当小文件比较多的时候,就会产生很多的元数据文件,一方面会大量占用NameNode 的内存空间,另一方面就是元数据文件过多,使得寻址索引速度变慢。

小文件过多,在进行 MR 计算时,会生成过多切片,需要启动过多的 MapTask。每个MapTask 处理的数据量小,导致 MapTask 的处理时间比启动时间还小,白白消耗资源

(3)解决方法

(1)使用 hive 自带的 concatenate 命令,自动合并小文件

使用方法:

#对于非分区表
alter table A concatenate;

#对于分区表
alter table B partition(day=20201224) concatenate;

(2)在数据采集的时候,就将小文件或小批数据合成大文件再上传 HDFS(数据源头)

(3)Hadoop Archive(存储方向)

通过HDFS的har归档文件进行归档,它将HDFS中一个个小文件归档成一个文件,对 NameNode 是一个整体,但是其内部实际上还是许多个小文件,减少了 NameNode 的内存。 具体看49题。

# 下面是Hive中的相关参数
#用来控制归档是否可用
set hive.archive.enabled=true;
#通知Hive在创建归档时是否可以设置父目录
set hive.archive.har.parentdir.settable=true;
#控制需要归档文件的大小
set har.partfile.size=1099511627776;

#使用以下命令进行归档
ALTER TABLE A ARCHIVE PARTITION(dt='2020-12-24', hr='12');

#对已归档的分区恢复为原文件
ALTER TABLE A UNARCHIVE PARTITION(dt='2020-12-24', hr='12');

(4)CombineTextInputFormat(计算方向)

CombineTextInputFormat 用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片,以减少切片的数量。

#执行Map前进行小文件合并
#CombineHiveInputFormat底层是 Hadoop的 CombineFileInputFormat 方法
#此方法是在mapper中将多个文件合成一个split作为输入
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 默认

#每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;   -- 256M

#一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;  -- 100M

#一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;  -- 100M

(5)开启 uber 模式,实现 JVM 重用(计算方向)

默认情况下,每个 Task 任务都需要启动一个 JVM 来运行,如果 Task 任务计算的数据量很小,我们可以让同一个 Job 的多个 Task 运行在一个 JVM 中,不必为每个 Task 都开启一个 JVM。

一个任务的JVM重用会一直开启,直到这个任务结束才会关闭重用的JVM

这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。

(6)使用Sequence file

图片
图片

sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。 和 HAR 不同的是,这种方式还支持压缩。该方案对于小文件的存取都比较自由,不限制文件的多少,但是 SequenceFile 文件不能追加写入,适用于一次性写入大量小文件的操作。

SequenceFile 仅仅能解决小文件问题,但这种数据格式的执行时间挺慢的(具体看16题)

17. Hive数据倾斜问题

参考:https://mp.weixin.qq.com/s?__biz=Mzg2MzU2MDYzOA==&mid=2247485154&idx=1&sn=cd7129544497c1a621e49dbc1d7ed5c3&scene=21#wechat_redirect

MapReduce和Spark中的数据倾斜解决方案原理都是类似的,以下讨论Hive使用MapReduce引擎引发的数据倾斜,Spark数据倾斜也可以此为参照。

(1)表连接时引发的数据倾斜

排除空值后,如果表连接的键存在倾斜,那么在 Reduce阶段必然会引起数据倾斜。

解决方案

通常做法是将倾斜的数据存到分布式缓存中,分发到各个Map任务所在节点。在Map阶段完成join操作,即MapJoin,从而减少了Reduce数据倾斜。

在Hive 0.11版本之前,如果想在Map阶段完成join操作,必须使用MAPJOIN来标记显示地启动该优化操作,由于其需要将小表加载进内存所以要注意小表的大小

如将a表放到Map端内存中执行,在Hive 0.11版本之前需要这样写:

select /* +mapjoin(a) */ a.id , a.name, b.age 
from a join b 
on a.id = b.id;

如果想将多个表放到Map端内存中,只需在mapjoin()中写多个表名称即可,用逗号分隔,如将a表和c表放到Map端内存中,则 /* +mapjoin(a,c) */

在Hive 0.11版本及之后,Hive默认启动该优化,也就是不在需要显示的使用MAPJOIN标记,其会在必要的时候触发该优化操作将普通JOIN转换成MapJoin,可以通过以下两个属性来设置该优化的触发时机:

hive.auto.convert.join=true 默认值为true,自动开启MAPJOIN优化。

hive.mapjoin.smalltable.filesize=2500000 默认值为2500000(25M),通过配置该属性来确定使用该优化的表的大小,如果表的大小小于此值就会被加载进内存中。

(2)空值引发的数据倾斜

实际业务中有些大量的null值或者一些无意义的数据参与到计算作业中,表中有大量的null值,如果表之间进行join操作,这样所有的null值都会被分配到一个reduce中,必然产生数据倾斜。

解决方案

方法一:异常数据时,空KEY过滤

很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空,

insert overwrite table jointable select n.* from (select 
* from nullidtable where id is not null) n left join bigtable o on n.id = 
o.id;

方法二:非异常数据时,空key转换

有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。由于null 值关联不上,处理后并不影响最终结果。

set mapreduce.job.reduces = 5;

insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on 
nvl(n.id,rand()) = o.id;

(3)Group By 引发的数据倾斜

如果group by 维度过小, Map 阶段同一 Key 有大量的数据分发给一个 reduce,很容易发生倾斜了。

两个参数:

  • hive.map.aggr=true:在map中会做部分聚集操作,效率更高但需要更多的内存。
  • hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

由上面可以看出起到至关重要的作用的其实是第二个参数的设置,它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上,所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜。

当然,也可以自己通过mapreduce程序来实现,即在 map 阶段将造成倾斜的key 先分成多组,例如 aaa 这个 key,map 时随机在 aaa 后面加上 1,2,3,4 这四个数字之一,把 key 先分成四组,先进行一次运算,之后再恢复 key 进行最终运算。

(4) Count(Distinct) 引发的数据倾斜

数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题

(5)不可拆分大文件引发的数据倾斜

当集群的数据量增长到一定规模,有些数据需要归档或者转储,这时候往往会对数据进行压缩;当对文件使用GZIP压缩等不支持文件分割操作的压缩方式,在日后有作业涉及读取压缩后的文件时,该压缩文件只会被一个任务所读取。如果该压缩文件很大,则处理该文件的Map需要花费的时间会远多于读取普通文件的Map时间,该Map任务会成为作业运行的瓶颈。这种情况也就是Map读取文件的数据倾斜。

解决方案:

这种数据倾斜问题没有什么好的解决方案,只能将使用GZIP压缩等不支持文件分割的文件转为bzip2等支持文件分割的压缩方式。

所以,我们在对文件进行压缩时,为避免因不可拆分大文件而引发数据读取的倾斜,在数据压缩的时候可以采用bzip2和Zip等支持文件分割的压缩算法

18. 请介绍一下Hive的严格模式

Hive的严格模式可以通过设置防止一些危险操作:

(1)分区表不使用分区过滤

hive.strict.checks.no.partition.filter 设置为 true 时,对于分区表,除非 where 语句中含有分区字段过滤条件来限制范围, 否则不允许执行。 换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。

(2)使用 order by 没有 limit 过滤

hive.strict.checks.orderby.no.limit 设置为 true 时,对于使用了 order by 语句的查询,要求必须使用 limit 语句。因为 order by 为了执行排序过程会将所有的结果数据分发到同一个Reducer 中进行处理(全局排序),强制要求用户增加这个 LIMIT 语句可以防止 Reducer 额外执行很长一段时间。

如果order by 后面用limit 2,相当于每个map只用两条数据,当数据多于两条时,将最小(或最大)哪一个扔掉,这样就减轻了reducer端执行负担。

(3)笛卡尔积

将 hive.strict.checks.cartesian.product 设置为 true 时, 会限制笛卡尔积的查询。 对关系型数据库非常了解的用户可能期望在 执行 JOIN 查询的时候不使用 ON 语句而是使用 where 语句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸的是, Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。

19. Hive索引有了解过吗

Hive支持索引(3.0版本之前),但是Hive的索引与关系型数据库中的索引并不相同,比如,Hive不支持主键或者外键。并且Hive索引提供的功能很有限,效率也并不高,因此Hive索引很少使用。

  • 索引适用的场景:

适用于不更新的静态字段。以免总是重建索引数据。每次建立、更新数据后,都要重建索引以构建索引表。

  • Hive索引的机制如下:

hive在指定列上建立索引,会产生一张索引表(Hive的一张物理表),里面的字段包括:索引列的值、该值对应的HDFS文件路径、该值在文件中的偏移量。

Hive 0.8版本后引入bitmap索引处理器,这个处理器适用于去重后,值较少的列(例如,某字段的取值只可能是几个枚举值) 因为索引是用空间换时间,索引列的取值过多会导致建立bitmap索引表过大。

注意:Hive中每次有数据时需要及时更新索引,相当于重建一个新表,否则会影响数据查询的效率和准确性,Hive官方文档已经明确表示Hive的索引不推荐被使用,在新版本的Hive中已经被废弃了

扩展:Hive是在0.7版本之后支持索引的,在0.8版本后引入bitmap索引处理器,在3.0版本开始移除索引的功能,取而代之的是2.3版本开始的物化视图,自动重写的物化视图替代了索引的功能。

20. Hive有哪些方式保存元数据,各有哪些特点

Hive支持三种不同的元存储服务器,分别为:内嵌模式、本地模式、远程模式

(1)、内嵌模式:将元数据保存在本地内嵌的derby数据库中,内嵌的derby数据库不支持多客户端访问

(2)、本地模式:将元数据保存在本地独立的数据库中(一般是mysql),这可以支持多会话连接。

(3)、远程模式:把元数据保存在远程独立的mysql数据库中,避免每个客户端都去安装mysql数据库。

三种配置方式区别

  • 内嵌模式使用的是内嵌的Derby数据库来存储元数据,也不需要额外起Metastore服务。这个是默认的,配置简单,但是一次只能一个客户端连接,适用于用来实验,不适用于生产环境。

  • 本地元存储和远程元存储都采用外部数据库来存储元数据,目前支持的数据库有:MySQL、Postgres、Oracle、MS SQL Server。在这里我们使用MySQL。

  • 本地元存储和远程元存储的区别是:本地元存储不需要单独启动metastore服务,用的是跟hive在同一个进程里的metastore服务远程元存储需要单独启动metastore服务,然后每个客户端都在配置文件里配置连接到该metastore服务。远程元存储的metastore服务和hive运行在不同的进程。

    metastore服务主要是用来连接mysql的

各有什么特点:

1.内存数据库derby,安装小,但是数据存在内存,不稳定

2.mysql数据库,数据存储模式可以自己设置,持久化好,查看方便。

21. 列式存储和行式存储

image-20210704164058899
image-20210704164058899

如图所示左边为逻辑表,右边第一个为行式存储,第二个为列式存储。

行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。

列存储的特点

因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法

TEXTFILE 和 SEQUENCEFILE 的存储格式都是基于行存储的;
ORC 和 PARQUET 是基于列式存储的。

22. Hive 中的压缩格式TextFile、SequenceFile、RCfile 、ORCfile、Parquet各有什么区别

(1)TextFile

默认格式,存储方式为行存储,数据不做压缩,磁盘开销大,数据解析开销大,可结合gzip、lzo、snappy、bzip2使用(系统自动检查,执行查询时自动解压),但是使用gzip、snappy,不会对数据进行切分,从而无法对数据进行并行操作。

TEXTFILE 和 SEQUENCEFILE 的存储格式都是基于行存储的。

(2)SequenceFile

Hadoop 的 HDFS 和 MapReduce 子框架主要是针对大数据文件来设计的,在小文件的处理上不但效率低下,而且十分消耗内存资源(每一个小文件占用一个 Block,每一个 block 的元数据都存储在 namenode 的内存里)。解决办法通常是选择一个容器,将这些小文件组织起来统一存储。HDFS 提供了两种类型的容器,分别是 SequenceFileMapFile

MapFile 是排序后的 SequenceFile

SeqeunceFile支持两种格式的数据压缩,分别是:record compressionblock compression

record compression是对每条记录的value进行压缩

img
img

block compression是将一连串的record组织到一起,统一压缩成一个block

image-20210627120216137
image-20210627120216137

一般建议使用BLOCK压缩

TEXTFILE 和 SEQUENCEFILE 的存储格式都是基于行存储的。

(3)RCFile
存储方式:数据按行分块,每块按列存储。结合了行存储和列存储的优点:
首先,RCFile 保证同一行的数据位于同一节点,因此元组重构的开销很低;
其次,像列存储一样,RCFile 能够利用列维度的数据压缩,并且能跳过不必要的列读取;

(4)ORCFile
存储方式:数据按行分块,每块按照列存储。
它是rcfile的改良版本, 效率比rcfile高, 压缩快、快速列存取。

TEXTFILE 和 SEQUENCEFILE 的存储格式都是基于行存储的,RCFile和ORCFile每块按列存储。

每个 Orc 文件由 1 个或多个 stripe 组成,每个 stripe一般为 HDFS的块大小,每一个 stripe 包含多条记录,这些记录按照列进行独立存储,对应到 Parquet中的 row group 的概念。每个 Stripe 里有三部分组成,分别是 Index Data,Row Data,Stripe Footer

  • Index Data:一个轻量级的 index,默认是每隔 1W 行做一个索引。这里做的索引应该只是记录某行的各字段在 Row Data 中的 offset。
  • Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个 Stream 来存储。
  • Stripe Footer:存的是各个 Stream 的类型,长度等信息。

(5)Parquet

Parquet 文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此 Parquet 格式文件是自解析的。

每个 Parquet 文件由 1 个或多个 Row Group组成。

  • 行组(Row Group):每一个行组包含一定的行数,在一个 HDFS 文件中至少存储一个行组,类似于 orc 的 stripe 的概念。
  • 列块(Column Chunk):在一个行组中每一列保存在一个列块中,行组中的所有列连续的存储在这个行组文件中。一个列块中的值都是相同类型的,不同的列块可能使用不同的算法进行压缩。
  • 页(Page):每一个列块划分为多个页,一个页是最小的编码的单位,在同一个列块的不同页可能使用不同的编码方式。

我们执行同样的SQL语句及同样的数据,只是数据存储格式不同,得到如下执行时长:

数据格式CPU时间用户等待耗时
TextFile33分171秒
SequenceFile38分162秒
Parquet2分22秒50秒
ORC1分52秒56秒

注:CPU时间:表示运行程序所占用服务器CPU资源的时间。
用户等待耗时:记录的是用户从提交作业到返回结果期间用户等待的所有时间。

查询TextFile类型的数据表耗时33分钟, 查询ORC类型的表耗时1分52秒,时间得以极大缩短,可见不同的数据存储格式也能给HiveSQL性能带来极大的影响。

23. Hive的UDF、UDAF、UDTF函数有什么区别

当 Hive 提供的内置函数无法满足你的业务处理需要时, 此时就可以考虑使用用户自定义函数(UDF:user-defined function)。

(1)UDF(User-Defined-Function)

单行进入,单行输出

(2)UDAF(User-Defined Aggregation Function)

聚集函数,多行进入,单行输出

(3)UDTF(User-Defined Table-Generating Functions)

一进多出

自定义函数的步骤:

  1. 继承 Hive 提供的类

    org.apache.hadoop.hive.ql.udf.generic.GenericUDF
    org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
    
  2. 实现类中的抽象方法,主要是evaluate方法,用于实现业务逻辑

  3. 在 hive 的命令行窗口创建函数

    # 添加jar包
    add jar /opt/module/data/myudf.jar;
    # 创建临时函数与开发好的 java class 关联
    create temporary function my_len as "com.layne.hive.MyStringLength";
    

24. Hive默认的分隔符是什么

把hive表格导出到本地时,系统默认的分隔符是^ACtrl+A,这个是特殊字符,直接cat或者vim是看不到的,用八进制编码\001表示。

25. hive中导入数据的几种方式

(1)向表中装载数据(Load)

加载本地文件到 hive

load data local inpath '/opt/module/hive/datas/student.txt' into table default.student;

加载 HDFS 文件到 hive 中

load data inpath '/user/layne/hive/student.txt' into table default.student;

加载数据覆盖表中已有的数据

load data inpath '/user/layne/hive/student.txt' overwrite overwrite table default.student;

(2)通过查询语句向表中插入数据(Insert)

基本插入数据

insert into table student_par values(1,'wangwu'),(2,'zhaoliu');

基本模式插入(根据单张表查询结果)

insert overwrite table student_par select id, name from student where month='201709';

insert into:以追加数据的方式插入到表或分区,原有数据不会删除
insert overwrite:会覆盖表中已存在的数据
注意:insert 不支持插入部分字段

多表(多分区)插入模式(根据多张表查询结果)

from student
insert overwrite table student partition(month='201707')
select id, name where month='201709'
insert overwrite table student partition(month='201706')
select id, name where month='201709'; 

(3)查询语句中创建表并加载数据(As Select)

根据查询结果创建表(查询的结果会添加到新创建的表中)

create table if not exists student3
as select id, name from student;

(4)创建表时通过 Location 指定加载数据路径

创建表,并指定在 hdfs 上的位置

create external table if not exists student5(
id int, name string
)
row format delimited fields terminated by '\t'
location '/student;

(5)Import 数据到指定 Hive 表中

一般配合export使用,做数据迁移时,先用 export 导出到HDFS后,再将数据导入

import table student2   
from '/user/hive/warehouse/export/student';

26. hive导出数据的几种方式

(1)Insert 导出

将查询的结果导出到本地(默认分隔符)

insert overwrite local directory '/opt/module/hive/data/export/student' select * from student;

将查询的结果格式化导出到本地(指定分割符)

insert overwrite local directory '/opt/module/hive/data/export/student1'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
select * from student;

将查询的结果导出到 HDFS 上(没有 local)

insert overwrite directory '/user/layne/student2' 
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;

(2)Hadoop 命令导出到本地

hive (default)> dfs -get /user/hive/warehouse/student/student.txt
/opt/module/data/export/student3.txt; 

(3)Hive Shell 命令导出

基本语法:(hive -f/-e 执行语句或者脚本 > file)

[layne@hadoop102 hive]$ bin/hive -e 'select * from default.student;' >
/opt/module/hive/data/export/student4.txt;

(4)Export 导出到 HDFS 上

export table default.student to '/user/hive/warehouse/export/student';

export 和 import 主要用于两个 Hadoop 平台集群之间 Hive 表迁移。

(5)Sqoop 导出

27. hive的执行计划有看过吗,你一般会关注哪几个点

参考:https://mp.weixin.qq.com/s?__biz=Mzg2MzU2MDYzOA==&mid=2247484152&idx=1&sn=7e48aa4a9650481f960c6cac234977a4&chksm=ce77f429f9007d3f9cd813f5576c2e751716d903af42d7d6b598edb4aa3045e0967de7e1d5c9&scene=178&cur_album_id=1688731294790139905#rd

先看一遍上面的文章,下面是我摘录的重点

HIVE提供了EXPLAIN命令来展示一个查询的执行计划,这个执行计划对于我们了解底层原理

  • EXTENDED:加上 extended 可以输出有关计划的额外信息。这通常是物理信息,例如文件名。这些额外信息对我们用处不大
  • DEPENDENCY:dependency在EXPLAIN语句中使用会产生有关计划中输入的额外信息。它显示了输入的各种属性

我重点关注,分为几个阶段和各个阶段的依赖

  1. stage dependencies: 各个stage之间的依赖性
  2. stage plan: 各个stage的执行计划

重点看,

  • Filter Operator下的predicate过滤条件

  • Map Join Operator的condition map(即join方式)

  • Select Operator下的Statistics统计信息(包含表中数据条数,数据大小)【输入的时候】

  • Group By Operator下的Statistics统计信息(包含分组聚合之后的数据条数,数据大小等)

  • File Output Operator下的Statistics统计信息(文件输出的信息)

统计信息重点看数据量的多少,一个Task是否会发生数据倾斜。这样就能判断任务的内存或单个task的内存是否充足。

28. Hive的两张表关联,使用MapReduce怎么实现

看hadoop的44题

1)reduce join : 在 map 阶段,map 函数同时读取两个文件 File1 和 File2,为了区分两种来源的 key/value 数据对,对每条数据打一个标签(tag),比如:tag=0 表示来自文件 File1,tag=2 表示来自文件 File2。 在 Reduce 端以连接字段作为 key 的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在 Map 阶段已经打标志)分开,最后进行合并就 ok 了。

2)map join : Map side join 是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们就可以采用 DistributedCache的方法,具体看上一题(hadoop的43题):Hadoop 的缓存机制(Distributedcache)

29. 写出hive中split、coalesce及collect_list函数的用法

split将字符串转化为数组,即:split(‘a,b,c,d’ , ‘,’) ==> [“a”,“b”,“c”,“d”]。

coalesce(T v1, T v2, …) 返回参数中的第一个非空值;如果所有值都为 NULL,那么返回NULL。

nvl只有两个参数,功能和coalesce一样。

collect_list列出该字段所有的值,不去重 => select collect_list(id) from table。

30. 使用过Hive解析JSON串吗

参考:https://mp.weixin.qq.com/s?__biz=Mzg2MzU2MDYzOA==&mid=2247485175&idx=1&sn=63f58dc2946678d4e50eb6e7bb3ff745&chksm=ce77f026f900793026c2ef23a466a59160c8f20230c01621e9eecad8911a5db9140ddf54354a&scene=178&cur_album_id=1800525691487076353#rd

先看一遍上面那个。

下面是我的总结

解析一个josn字符串,可以用:

  1. get_json_object(json_string, '$.key') 一次只能解析json中的一个字段
  2. json_tuple(json_string, k1, k2 ...) 一次可以解析json中的多个字段

如果要解析一个json数组,可以:

  1. 通过regexp_replace、split、explode将json数组转化为多个json字符串
  2. 使用子查询的方式,结合json_tuple或get_json_object函数来解析json里面的字段

例如:

select json_tuple(json, 'website', 'name') 
from (
select explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]', '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')) 
as json) t;


select get_json_object(json, '$.website'),get_json_object(json, '$.name')
from (
select explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]', '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))
as json) t;

注意,不能json_tuple(explode(split(regexp_replace,因为explode是UDTF,UDTF函数不能写在别的函数内,也就是这里的explode函数不能写在json_tuple里面。所以要结合子查询方式

另外,也可以结合LATERAL VIEW解析具有对应关系的json数组,如下:

hive表中 goods_id 和 json_str 字段的内容如下:

goods_idjson_str
1,2,3[{“source”:“7fresh”,“monthSales”:4900,“userCount”:1900,“score”:“9.9”},{“source”:“jd”,“monthSales”:2090,“userCount”:78981,“score”:“9.8”},{“source”:“jdmart”,“monthSales”:6987,“userCount”:1600,“score”:“9.0”}]

31. 请说出Hive运行的三种引擎

Tez可以将多个有依赖的作业转换为一个作业,这样只需写一次HDFS,且中间节点较少,从而大大提升作业的计算性能。

Mr/tez/spark区别:

Mr引擎:多job串联,基于磁盘,落盘的地方比较多。虽然慢,但一定能跑出结果。一般处理,周、月、年指标。

Spark引擎:虽然在Shuffle过程中也落盘,但是并不是所有算子都需要Shuffle,尤其是多算子过程,中间过程不落盘 DAG有向无环图。 兼顾了可靠性和效率。一般处理天指标。

Tez引擎:完全基于内存。 注意:如果数据量特别大,慎重使用。容易OOM。一般用于快速出结果,数据量比较小的场景。