1.Hive基本介绍
1.1 Hive简介
之前有讲过数据仓库的概念,主要就是按主题划分结构。
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射成一张数据库表,并提供类SQL查询功能。
通俗来讲就是,我们把需要的数据按照一定的主题拉取到数据仓库中去,数据仓库的底层是Hadoop的HDFS存储,而它的表层会把这种结构化的文件映射成数据库表,然后提供给我们类SQL的查询。
1.2 Hive为什么会出现
前面说它是基于Hadoop的,所以它实际上是Hadoop的一种表层应用,如果我们直接使用Hadoop,MapReduce的直接编写复杂繁难。
而我们程序员对于SQL语句更为熟悉,如果我们可以直接编写SQL,而不用去关心SQL怎么转换成MapReduce的函数的,对于开发会提高不少效率。
所以Hive基于以上需求出现了。
1.3Hive特点
Hive的底层是Hadoop的MapReduce,而MapReduce的底层是HDFS,这也决定了Hive的某些特点。
- 可扩展: Hive可以自由的扩展集群规模,一般不用重启服务,这个特点就是基于分布式的HDFS文件存储。
- 延展性: Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数,但是一般情况下Hive内嵌的函数已经足够我们使用了。
- 容错性: Hive的某个节点出了问题,依然可以继续执行sql,这个也是基于Hadoop的分布式节点的原理。
2. Hive原理
2.1 基础架构
其实Hive的架构图还是较为清晰简单的,底层Hadoop,表层Hive。
从上往下来看
- CLI/JDBC/ODBC/WebGUI:这些都是用户接口,用于访问与操作Hive。
- Metastore:这个是元数据存储。元数据简单来说就是一些定义相关的信息,例如:表名、表列、分区、属性、数据目录等等,这些信息实际上是存储在关系型数据库中,例如MySql。
- 扩展: 这里需要明白为什么Hive要设计这个东西?
元数据不管是显示还是我们开发都会用到,而元数据存储在Mysql中,用户在获取的时候可以直接去连接metastore,并且支持多个客户端同时连接,用户在连接的时候也不需要知道Mysql的用户名密码,只需要连接它的服务即可。
- 扩展: 这里需要明白为什么Hive要设计这个东西?
- Driver:这个就是驱动了,包含了解释器、编译器、优化器完成HQL查询从词法分析、语法分析、编译、优化以及查询计划的生成,生成的查询计划存储在HDFS中,并在随后由MapReduce调用执行。
2.2 具体特点
- 查询语言:前面已经提到过,Hive是为了解决MapReduce需要编写一堆繁难的代码而出现,所以它设计了类SQL的查询语言,让学习开发成本大大降低。
- 数据存储:Hive的数据都是存储在HDFS上的,我们利用HUE或者是SHELL看到的表结构的样式,实际上是根据元数据去显示的,一个Hive表中的数据可能分布在不同的HDFS节点上,而不同Hive表中的数据也可能分布在同一个节点上,这个是根据表大小以及定义去决定的。
- 数据格式:Hive并没有专门的数据格式,数据格式可以由用户指定,加载数据的过程中,不需要从用户数据格式到Hive定义的数据格式的转换,所以,Hive在加载过程中不会对数据做任何修改,而只是将数据复制或移动到相应的HDFS目录中。
- 数据更新:Hive是针对数据仓库应用设计的,数据仓库又是读多写少,所以Hive不支持数据的改写添加,数据在加载的时候是确定好的。
- 索引:Hive之前是没有索引的,由于它在访问数据中满足条件的特定值时,需要暴力的扫描整个表,但是由于MapReduce,Hive可以并行访问数据,所以没有索引也可以体现出Hive的优势,但是Hive的高延迟也是不可避免的,所以它不适用于在线数据查询。
- 执行:Hive中的查询基本都是由底层Hadoop的MapReduce来实现的。
- 数据规模:由于MapReduce的特性,Hive可以支持很大规模的数据查询。
2.3 执行流程
执行的关键点就在于怎么把HQL转换成MapReuce执行
简化版的图一目了然,接着剖析一下下面详细版流程图。
- Execute Query:从UI(一般为HUE)或是其他的Hive接口将查询发送给Driver来执行。
- GetPlan:Driver借助查询编译器解析查询,检查语法和查询计划或查询需求
- Get Metadata:获取元数据,编译器将查询元数据请求发送给Metastore。
- Send Metadata:Metastore将元数据作为对编译器的响应发送出去。
- SendPlan:编译器检查需求并且将计划重新发送给Driver,到了这里,查询的解析和变异都已经完成。
- Execute Plan:Driver将执行计划发送给执行引擎。
6.1 executeJob:正式开始执行任务,JobTracker会分配监控MapReduce任务并执行,(MapReduce的执行流程可以移步我之前的博客——MapReuce详解)。
6.1 metaDataOps for DDLs: 任务执行的同时,执行引擎可以使用Metastore执行元数据操作。
6.2 jobDone:当底层的MapReduce执行完成后,会将结果返回给执行引擎。
6.3 dfs operations:这个就是Hadoop的命令,直接作用于文件系统,执行引擎利用这个命令和HDFS交互。 - FetchResult:执行引擎将把结果反馈给UI或其他接口。
- SendResults:执行引擎将结果发送给Driver。
- fetchResult:执行引擎将结果存储在HDFS上。
2.3 Hive编译过程
这个编译过程就是将HQL转换成MapReduce任务计划的过程,也是Hive比较重要的一点。
我们举个例子
select * from dim.dim_region where dt = '2019-05-30'
这个sql很简单,对5.30的地区维度表查询,这个sql会经历以下过程
- 转换为AST Tree: 根据Antlr定义的sql语法规则,进行解析。
ABSTRACT SYNTAX TREE:
TOK_QUERY
TOK_FROM
TOK_TABREF
TOK_TABNAME
dim
dim_region
TOK_INSERT
TOK_DESTINATION
TOK_DIR
TOK_TMP_FILE
TOK_SELECT
TOK_SELEXPR
TOK_ALLCOLREF
TOK_WHERE
=
TOK_TABLE_OR_COL
dt
'2019-05-30'
- 遍历AST Tree,抽象出QueryBlock:对AST进行进一步的抽象和结构化,形成QueryBlock,这个是基本组成单元包含三个部分,输入源,计算过程,输出,Block的生成过程是一个递归过程,先序遍历AST Tree,遇到不同的Token节点,保存到相应的属性中,主要包含以下过程
- TOK_QUERY:创建 QB 对象,循环递归子节点
- TOK_FROM:将表名语法部分保存到 QB 对象的 aliasToTabs 等属性中
- TOK_INSERT:循环递归子节点
- TOK_DESTINATION:将输出目标的语法部分保存在 QBParseInfo 对象的nameToDest 属性中
- TOK_SELECT:分别将查询表达式的语法部分保存在 destToSelExpr 、destToAggregationExprs 、 destToDistinctFuncExprs 三个属性中
- TOK_WHERE:将 Where 部分的语法保存在 QBParseInfo 对象的destToWhereExpr 属性中
- 遍历QueryBlock,翻译为执行操作树OperatorTree:MapReduce的任务执行都有OperatorTree组成。
- Logical Optimizer对OperatorTree进行优化操作:使用ReduceSinkOperator,减少shuffle数据量。大部分逻辑层优化器通过变换 OperatorTree ,合并操作符,达到减少 MapReduce Job ,减少 shuffle 数据量的目的。
- 遍历OperatorTree,并翻译为MapReduce任务:
OperatorTree 转化为 Task tree的过程分为下面几个阶段:- 对输出表生成 MoveTask
- 从 OperatorTree 的其中一个根节点向下深度优先遍历
- ReduceSinkOperator 标示 Map/Reduce 的界限,多个 Job 间的界限
- 遍历其他根节点,遇过碰到 JoinOperator 合并 MapReduceTask
- 生成 StatTask 更新元数据
- 剪断 Map 与 Reduce 间的 Operator 的关系
- 物理层优化器对MapReduce任务进行优化,生成最终执行计划。
总结
其实Hive的原理还是很简单的,主要的难点就是MapReduce的转换,还有和Hadoop的交互,还有就是Hive是一个数据仓库,我们在学习Hive之前一定要对维度,指标,事实表等大数据的名词有一个很清晰的概念。
至于Hive的使用,相信大家都会Sql,使用起来上手相当容易,另外,Hive一般都和HUE配套使用,来作为Hive的可视化操作界面,类似于MySql的Navicat,很方便。