Hadoop之Hive

x33g5p2x  于2020-10-30 发布在 Hive  
字(16.7k)|赞(0)|评价(0)|浏览(925)

1**、Hive概述**

Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的SQL查询功能,可以将SQL语句转换为MapReduce任务进行执行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。Hive提供了一系列的工具,可以用来进行数据提取转化加载(这个过程通常叫做ETL),这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。Hive定义了简单的类SQL查询语言,称为HQL,它允许熟悉SQL的用户查询数据,同时,这个语言也允许熟悉MapReduce的开发者开发自定义的MapReduce程序来处理内建的Hive函数无法完成的复杂的分析工作。

Hive构建在基于静态批 的Hadoop之上,Hadoop通常具有较高的延迟并且在作业提交和调度时需要大量的开销,因此,Hive并不能在大规模数据集上实现低延迟的查询,例如,Hive在几百MB的数据集上执行查询一般会有分钟级的延迟。Hive不适合那些需要低延迟的应用,如联机事务处理(OLTP)。Hive查询操作过程严格遵守Hadoop MapReduce的作业执行模型,Hive将用户的HiveQL语句通过解释器转换为MapReduce作业提交到Hadoop集群上,Hadoop监控作业的执行过程,然后返回作业执行结果给用户。Hive并非为联机事务处理而设计,Hive并不提供实时的查询和基于行级的数据更新操作,Hive的最佳使用场合是大数据集的批处理作业,例如网络日志分析等。

Hive是一种底层封装了Hadoop的数据仓库处理工具,使用类SQL的HiveQL语言实现数据查询,所有Hive的数据都存储在Hadoop兼容的文件系统中。Hive在加载数据过程中不会对数据进行任务的修改,只是将数据移动到HDFS中Hive设定的目录下,因此,Hive不支持对数据的改写和添加,所有的数据都是在加载的时候确定的。Hive的设计特点如下:

支持索引,加快数据查询;
*
支持不同的存储类型,如纯文本文件、HBase中的文件;
*
将元数据保存在关系型数据库中,大大减少在查询过程中执行语义检查的时间;
*
可以直接使用存储在Hadoop文件系统中的数据;
*
内置大量用户函数UDF来操作时间、字符串,并提供其他的数据挖掘工具,支持用户扩展UDF函数来完成内置函数无法完成的操作;
*
类SQL的查询方式,将SQL查询转换为MapReduce的job在Hadoop集群上执行。

2**、Hive的体系结构**

Hive的体系结构主要分为四个部分:用户接口/界面、元数据存储、执行引擎以及Hadoop部分。

(1)用户接口/界面主要有三个,即CLI,JDBC/ODBC以及WebUI

CLI,也就是Hive的Shell命令行(Hive的客户端),这是最常使用的一种方式,CLI启动的时候,会同时启动一个Hive副本;
*
JDBC/ODBC是Hive的Java,与使用传统数据库JDBC编程的方式类似;
*
WebUI是通过浏览器访问Hive。

(2)元数据存储

Hive将元数据存储在数据库中(MetaStore),如MySQL、Oracle、derby。Hive中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等。

(3)执行引擎

执行引擎包含多个功能部分,如编译器、优化器、执行器等,它们完成HQL查询语句从词法分析、语法分析、编译、优化以及查询计划(Plan)的生成,生成的查询计划存储在HDFS中,并随后由MapReduce调用执行。

(4)Hadoop****部分

Hive的Hadoop部分主要包含两块,即MapReduce和HDFS,Hive中的大部分查询由MapReduce完成(注意,包含/的查询,比如select / from table不会生成相应的MapReduce任务),而其数据则存储在HDFS中。

下图简单地描述了整个Hive的体系结构。

3**、Hive的工作原理**

下图描述了Hive和Hadoop之间的工作流程。

Hive与Hadoop交互过程解析如下:
Step No.

操作1

Execute Query

Hive用户接口,如命令行或Web UI等发出查询命令,驱动程序(如JDBC,ODBC等驱动程序)来执行。2

Get Plan

在驱动程序帮助下查询编译器,分析查询语法、查询计划或查询的要求。3

Get Metadata

编译器发送查询元数据请求到MetaStore(Hive支持的数据库)。4

Send Metadata

MetaStore返回元数据结果给编译器。5

Send Plan

编译器检查查询要求,并返回计划给驱动程序,到此为止,查询解析和编译完成。6

Execute Plan

驱动程序发送执行计划到执行引擎。7

Execute Job

在Hadoop内部,执行作业的过程是一个MapReduce程序执行的过程。执行引擎发送作业给JobTracker,名称节点把作业分配到TaskTracker,由数据节点执行。7

Metadata Ops

与此同时,在MapReduce执行过程中,执行引擎可以通过MetaStore执行元数据相关操作。8

Fetch Result

执行引擎接收来自数据节点的执行结果。9

Send Results

执行引擎返回查询结果给驱动程序。10

Send Results

驱动程序将查询结果返回给Hive用户接口端。

4**、Hive的数据类型**

A**、基本数据类型**

Hive支持的基本数据类型与Java中的类似,主要有整数类型、浮点类型、布尔类型、字符串类型,描述如下:

tinyint/smallint/int/bigint:整数类型
*
float/double:浮点数类型
*
boolean:布尔类型
*
string:字符串类型

B**、复杂数类型**

Hive中有4种复杂类型的数据结构,即Array、Map、Struct以及Union,描述如下:

Array:数组类型,由一系列相同数据类型的元素组成,与Java类似;
*
Map:集合类型,包含<key,value>键值对,可以通过key访问元素,key只能是基本数据类型,值可以是任意类型;
*
Struct:结构类型,可以包含不同数据类型的元素,这些元素可以通过“.”点语法的方式来进行访问;
*
Union:联合类型,类似于C语言中的union结构,在给定的任何一个时间点,Union类型可以保存指定数据类型中的任意一种。

C**、时间类型**

Hive中的时间类型主要有两种,即Date和Timestamp,如下:

Date:日期类型,描述特定的年/月/日,格式为yyyy-mm-dd,例如2018-7-8,Date类型只能在Date、Timestamp和String类型之间转换,从Hive0.12.0版本开始支持;
*
Timestamp:时间戳类型,它支持传统的Unix时间戳和可选的纳秒精度,

被存储为从Unix纪元的偏移量,从Hive0.8.0版本开始支持。

5**、Hive的安装和配置**

Hive的安装模式总共有三种,即内嵌模式、本地模式以及远程模式,本地模式和远程模式比较接近,都需要使用第三方数据库类存储元数据,这三种安装模式的区别总结如下:

内嵌模式:内嵌模式使用的是内嵌的Derby数据库来存储元数据,也不需要额外起MetaStore服务。这个是默认的,配置简单,但是一次只能一个客户端连接,适用于实验,不适用于生产环境;
*
本地模式:本地元存储和远程元存储都采用外部数据库来存储元数据,本地元存储不需要单独起MetaStore服务,用的是跟Hive在同一个进程里的MetaStore服务。目前Hive支持的数据库有:MySQL、Oracle、MS SQLServer等,在本文中我们将使用MySQL;
*
远程模式:远程模式与本地模式的最大区别就是,远程元存储需要单独起MetaStore服务,然后每个客户端都在配置文件里配置连接到该MetaStore服务。远程元存储的MetaStore服务和Hive运行在不同的进程中。

由于本地模式和远程模式在使用上基本没有区别,因此本文仅介绍内嵌模式和本地模式的安装和配置。

A**、内嵌模式**

内嵌模式是将元信息存储在Hive内置的Derby数据库中,并且一次只能允许一个客户端进行连接,在实际场景中比较少使用。下面在主机hadoop221上安装和部署Hive的内嵌模式。

首先,将Hive安装包上传到主机Hadoop的/root/tools目录下,运行命令tar -zxvfapache-hive-2.3.0-bin.tar.gz -C /root/training/,将Hive解压到/root/training目录下;然后,配置Hive的环境变量,运行命令vi /root/.bash_profile,在末尾添加如下内容:

HIVE_HOME=/root/training/apache-hive-2.3.0-bin

export HIVE_HOME

PATH=$HIVE_HOME/bin:$PATH

export PATH

保存退出后,运行命令source /root/.bash_profile,使环境变量生效;下面配置Hive的核心配置文件,进入到/root/training/apache-hive-2.3.0-bin/conf目录,运行命令vi hive-site.xml创建一个文件,并在其中输入以下内容:

<?xmlversion="1.0" encoding="UTF-8"standalone="no"?>

<?xml-stylesheettype="text/xsl" href="configuration.xsl"?>

<configuration>

<!--连接的URL地址,并指定数据库的名字为metastore,create=true表示如果数据>库不存在,就自动创建-->

<property>

<name>javax.jdo.option.ConnectionURL</name>

<value>jdbc:derby:;databaseName=metastore_db;create=true</value>

</property>

<!--指定驱动的名字-->

<property>

<name>javax.jdo.option.ConnectionDriverName</name>

<value>org.apache.derby.jdbc.EmbeddedDriver</value>

</property>

<!--指定是否使用本地数据库存储元信息-->

<property>

<name>hive.metastore.local</name>

<value>true</value>

</property>

<!--指定元信息数据保存的位置-->

<property>

<name>hive.metastore.warehouse.dir</name>

<value>file:///root/training/apache-hive-2.3.0-bin/warehouse</value>

</property>

</configuration>

Hive嵌入模式的安装,需要配置的参数总结如下表:
参数文件

配置参数

参考值hive-site.xml

javax.jdo.option.ConnectionURL

jdbc:derby:;databaseName=metastore_db;create=truejavax.jdo.option.ConnectionDriverName

org.apache.derby.jdbc.EmbeddedDriverhive.metastore.local

truehive.metastore.warehouse.dir

file:///root/training/apache-hive-2.3.0-bin/warehouse

保存退出后,接下来需要初始化Hive内置的Derby数据库,以在配置的元信息保存目录/root/training/apache-hive-2.3.0-bin/warehouse,生成相应的数据,这个操作的本质其实就是调用Hive自带的一个脚本,创建相应的数据库和表等。运行命令schematool-dbType derby –initSchema,初始化Derby数据库,如下图所示,从输出的log信息也可以看出,这个初始化操作是调用了hive-schema-2.3.0.derby.sql脚本,在当前目录下创建了metastore_db数据库(Hive中的数据库对应于目标存储系统的一个目录)。

到这里为止,Hive的嵌入模式便安装完成。最后,测试下Hive是否安装成功。由于Hive的运行依赖Hadoop,先确保Hadoop已经启动,然后运行命令hive,启动Hive的Shell命令行,运行命令create table student(tid int, tname string);创建一个student表;运行命令insert into table studentvalues(01,'zhangsan');往student表中插入一条数据,如下图所示,可以看到插入数据时启动了一个MapReduce任务,但是最终数据是保存在本地Linux文件系统中。

B、本地模式

Hive的本地模式是将元信息保存在第三方数据库中,因此,在安装Hive的本地模式之前,需要先安装一个关系型数据库,这里选择MySQL数据库。下面先来安装和配置MySQL数据库。

首先,将MySQL的安装包上传到主机Hadoop221的/root/tools目录下,运行命令tar -xvfmysql-5.7.19-1.el7.x86_64.rpm-bundle.tar,将MySQL解压到当前目录下,由于在安装Linux系统时,已经安装了MySQL的一些驱动及lib库,需要将这些都卸载掉,运行命令yum remove mysql-libs,然后依次运行下面这些命令:

rpm -ivh mysql-community-common-5.7.19-1.el7.x86_64.rpm
*
rpm -ivh mysql-community-libs-5.7.19-1.el7.x86_64.rpm
*
rpm -ivh mysql-community-client-5.7.19-1.el7.x86_64.rpm
*
rpm -ivh mysql-community-server-5.7.19-1.el7.x86_64.rpm
*
rpm -ivh mysql-community-devel-5.7.19-1.el7.x86_64.rpm (可选)

然后,启动MySQL数据库,运行命令service mysqld start或systemctl startmysqld.service,MySQL启动时会自动创建一个root用户,并且随机创建一个密码,为方便记忆,需要修改该密码。运行命令cat /var/log/mysqld.log | grep password,查看root用户的临时密码,运行命令mysql –uroot –p,然后输入root用户的临时密码登录到mysql,运行命令alter user 'root'@'localhost'identified by 'Welcome_1';修改root用户的密码为Welcome_1,;运行命令create database hive;创建一个名叫hive的数据库,后续在Hive中需要使用该数据库;运行命令create user 'hiveowner'@'%' identified by 'Welcome_1';创建一个名叫hiveowner,密码为Welcome_1的用户来管理hive数据库;最后,依次运行命令grant all on hive./* TO'hiveowner'@'%';和grant all on hive./* TO'hiveowner'@'localhost' identified by 'Welcome_1';为hiveowner用户授予权限,使其能够访问hive数据库。

到此为止,MySQL数据库的安装和配置完成。前面已经安装了Hive的嵌入模式,现在在其基础上来安装Hive的本地模式。进入到/root/training/apache-hive-2.3.0-bin/conf目录下,运行命令vi hive-site.xml,将其中的内容替换为如下内容:

<?xmlversion="1.0" encoding="UTF-8"standalone="no"?>

<?xml-stylesheettype="text/xsl" href="configuration.xsl"?>

<configuration>

<!--指定JDBC的URL地址,注意useSSL=false,SSL是一种安全加密协议,如需使用SSL>,需要进行额外配置,这里简单起见配置为false,不启用SSL-->

<property>

<name>javax.jdo.option.ConnectionURL</name>

<value>jdbc:mysql://localhost:3306/hive?useSSL=false</value>

</property>

<!--指定驱动为JDBC驱动-->

<property>

<name>javax.jdo.option.ConnectionDriverName</name>

<value>com.mysql.jdbc.Driver</value>

</property>

<!--指定连接MySQL数据库使用的用户名为hiveowner-->

<property>

<name>javax.jdo.option.ConnectionUserName</name>

<value>hiveowner</value>

</property>

<!--指定连接MySQL数据库使用的用户hiveowner对应的密码Welcome_1-->

<property>

<name>javax.jdo.option.ConnectionPassword</name>

<value>Welcome_1</value>

</property>

</configuration>

Hive本地模式的安装,需要配置的参数总结如下表:
参数文件

配置参数

参考值hive-site.xml

javax.jdo.option.ConnectionURL

jdbc:mysql://localhost:3306/hive?useSSL=falsejavax.jdo.option.ConnectionDriverName

com.mysql.jdbc.Driverjavax.jdo.option.ConnectionUserName

hiveownerjavax.jdo.option.ConnectionPassword

Welcome_1

保存退出,由于这里使用MySQL数据库来保存Hive的元信息,需要连接MySQL数据库,因此需要将MySQL的连接驱动拷贝到Hive安装目录的lib目录下。这里需要注意,由于Hive与MySQL版本兼容性的问题,使用低版本的MySQL连接驱动会出问题,需要使用较高版本才行,推荐使用5.1.43以上版本。最好是在官网上下载最新的版本,我这里在官网下载了最新版本,如mysql-connector-java-5.1.46。

跟前面Hive内嵌模式的安装类似,这里需要对MySQL数据库进行初始化,注意:如果使用的是老版本的Hive,不需要这步初始化的操作,第一次启动Hive的时候会自动进行初始化。运行命令schematool -dbType mysql–initSchema,对MySQL数据库进行初始化,如下图所示,可以看到这里调用了hive-schema-2.3.0.mysql.sql脚本,在MySQL数据库中创建了相应的表,用于存放Hive的元信息。

到这里为止,Hive的本地模式安装完成。最后,测试下Hive是否安装成功。运行命令hive,启动Hive的Shell命令行,运行命令createtable student(tid int, tname string);创建一个student表;运行命令insert into table student values(01,'zhangsan');往student表中插入一条数据,如下图所示,可以看到插入数据时启动了一个MapReduce任务,最终数据保存在HDFS文件系统中,如下图所示。可以看到,Hive自动在HDFS的目录/user下创建了hive/warehouse/student/000000_0对应的目录和文件,来保存Hive中的表数据,而表的元信息(如表名称,列名称以及数据类型等信息)则保存到MySQL数据库中。

6**、Hive的数据模型**

A**、Hive的数据存储**

Hive 没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由的组织Hive中的表,只需要在创建表的时候指定Hive数据中的列分隔符和行分隔符,Hive 就可以解析数据。在Hive中,数据存储的特定简单总结为以下几点:

数据存储基于HDFS;
*
没有专门的数据存储格式;
*
存储结构主要包括:数据库、文件、表、视图;
*
可以直接加载文本文件(如.txt文件);
*
创建表时,需要指定Hive数据的列分隔符和行分隔符。

Hive中的数据库相当于关系型数据库中的命名空间(namespace),它的作用是将用户和数据库的应用隔离到不同的数据库或模式中;Partition对应于数据库中的 Partition 列的密集索引,但是 Hive 中Partition的组织方式和数据库中的很不相同,在 Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition的数据都存储在对应的目录中;Bucket对指定列计算hash,根据hash值切分数据,目的是为了并行(尽可能将数据分散存储,避免热块),每一个Bucket对应一个文件。

Table的创建过程和数据加载过程(这两个过程可以在同一个语句中完成),在加载数据的过程中,实际数据会被移动到数据仓库目录中(相当于剪切,原始数据文件不再存在),之后对数据的访问将会直接在数据仓库目录中完成;删除表时,表中的数据和元数据将会被同时删除。External Table只有一个过程,加载数据和创建表同时完成,实际数据是存储在指定的HDFS路径中,并不会移动到数据仓库目录中。

下面以员工表employee为例,结合实例操作,介绍Hive中的几种数据模型,员工表中的数据内容如下图所示:

B、Inner Table(内部表)

Hive中的内部表也叫托管表,这种表的数据文件存储在Hive的数据仓库中,其特点简单总结如下:

与数据库中的Table在概念上类似;
*
每一个Table在Hive中都有一个相应的目录存储数据;
*
所有的Table数据(不包括External Table)都保存在这个目录中;
*
删除表时,元数据和表中数据都会被删除。

实例:在Hive中创建一个员工表emp,并使用‘,’作为列分隔符,HQL语句如下:

createtable emp(empno int,ename string,

jobstring,managerno int,hiredate string,

salaryint,bonus int,deptno int)

rowformat delimited fields terminated by ',';

运行结果如下图所示:

C、External Table(外部表)

外部表的数据文件可以存放在Hive数据仓库外部的分布式文件系统中,也可以存放到Hive数据仓库中(注意:Hive的数据仓库也就是HDFS中的一个目录,这个目录是Hive数据文件存储的默认路径,它可以在Hive的配置文件中进行配置,最终也会存放到元数据库中),其特点简单总结如下:

指向已经在HDFS中存在的数据文件,可以创建Partition;
*
它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异;
*
外部表只有一个过程,加载数据和创建表同时完成,并不会将数据文件移动到数据仓库目录中,只是与外部数据文件建立一个链接,当删除一个外部表时,也仅删除该链接。

实例:在Hive中创建一个外部表emp_ext,样使用‘,’作为列分隔符,并指定数据路径为‘/root/data/employee’,HQL语句如下:

createtable emp_ext(empno int,ename string,

jobstring,managerno int,hiredate string,

salaryint,bonus int,deptno int)

rowformat delimited fields terminated by ','

location'/root/data/employee';

运行结果如下图所示:

D**、分区表**

Hive里分区的概念,是根据“分区列”的值对表的数据进行粗略划分的机制,在Hive存储上就体现在表的主目录下的一个子目录,这个文件夹的名字就是我们定义的分区列的名字,没有实际操作经验的人可能会认为分区列是表的某个字段,其实不是这样,分区列不是表里的某个字段,而是独立的列,我们根据这个列存储表里的数据文件。分区是为了加快数据分区的查询速度而设计的,当我们在查询某个具体分区列里的数据时,就没必要进行全表扫描,其特点简单总结如下:

Partition对应于数据库的Partition列的密集索引;
*
在Hive中,表中的一个Partition对应于表下的一个目录,所有的 Partition的数据都存储在对应的目录中。

实例:在Hive中创建一个分区表,同样使用‘,’作为列分隔符,并以部门号deptno列创建分区,HQL语句如下:

createtable emp_part(empno int,ename string,

jobstring,managerno int,hiredate string,

salaryint,bonus int)

partitionedby (deptno int)

rowformat delimited fields terminated by ',';

运行结果如下图所示:

E**、Bucket Table(桶表)**

上面的table和partition都是目录级别的拆分数据,Bucket则是对数据源文件本身进行拆分数据,使用桶的表会将源数据文件按一定规律拆分成多个文件,要使用Bucket,我们需要打开Hive对桶的设置,其特点总结如下:

桶表是对数据进行哈希取值,然后存放到不同文件中;
*
需要设置环境变量:sethive.enforce.bucketing = true;。

实例:在Hive中创建一个桶表,同样使用‘,’作为列分隔符,并根据职务job列的值创建5个Bucket,HQL语句如下:

createtable emp_bucket(empno int,ename string,

jobstring,managerno int,hiredate string,

salaryint,bonus int,deptno int)

clusteredby (job) into 5 buckets

rowformat delimited fields terminated by ',';

运行结果如下图所示:

F**、View(视图)**

Hive视图是一种无关底层存储的逻辑对象,视图中的数据是select查询返回的结果,在视图选定后才会开始执行select查询。需要注意的是,视图是只读的,不能向视图中插入或者加载数据。通过引入视图机制,用户可以将注意力集中在其关心的数据上(而非全部数据),这样就大大提高了用户效率与用户满意度,而且如果这些数据来源于多个基本表结构,或者数据不仅来自于基本表结构,还有一部分数据来源于其他视图,并且搜索条件又比较复杂时,需要编写的查询语句会比较繁琐,此时定义视图就可以使数据的查询语句变得简单可行。简言之,定义视图可以将表与表之间的复杂的操作连接和搜索条件对用户不可见,用户只需要简单地对一个视图进行查询即可,故增加了数据的安全性,但不能提高查询效率。视图的特定简单总结如下:

视图是一种虚表,是一个逻辑概念;可以跨越多张表;
*
视图建立在已有表的基础上,视图赖以建立的这些表称为基表;
*
视图可以简化复杂的查询,但不能提高查询效率。

实例:在Hive中,基于从emp表中查询empno和ename两个列的所有数据,创建一个视图myview(注意,先前创建的emp表并未导入数据,关于如何导入数据后文会做介绍,这里先运行命令load data local inpath '/root/data/employee' into table emp;从本地导入数据以用于实验),HQL语句为create view myview as selectempno,ename from emp;然后,从视图myview中查询所有的员工姓名,HQL语句为:select ename from myview;,运行结果如下图所示:load data local inpath '/root/data/employee' into table emp;

7**、Hive数据的导入**

从严格意义上来说,Hive中主要支持两种方式导入数据,其一,使用load语句导入数据;其二,使用sqoop导入关系型数据库中的数据。下面分别针对这两种方式简单做介绍。

A**、使用load语句导入数据**

使用load语句导入数据又可以分为两种情况,一种是导入本地的数据文件,另一种是导入HDFS上的数据文件。前面,已经基于数据表employee的格式,在Hive中创建了对应的emp表,现在从本地文件系统中将employee数据表导入到emp表中,运行命令load data local inpath '/root/data/employee' into table emp;运行结果如下图所示:

从HDFS中将employee数据表导入到emp表中类似,运行命令load data inpath '/data/employee' into table emp;即可,可以看到,此时再去查看HDFS中的/data目录,employee文件不复存在。注意:Hive默认的分隔符是:tab键,所以在创建表的时候,如果数据表文件中的数据不是以tab键分隔,需要指定分隔符。

B**、使用sqoop导入关系型数据库中的数据**

将关系型数据表的表结构复制到Hive中

sqoop create-hive-table --connectjdbc:mysql://hadoop221:3306/test --table username --username root --password123456 --hive-table test

其中 --table username为mysql中的数据库test中的表 --hive-table test 为hive中新建的表名称

从关系型数据库导入文件到hive中

sqoop import --connect jdbc:mysql://hadoop221:3306/test--username root --password mysql-password --table t1 --hive-import

将hive中的表数据导入到mysql中

sqoop export --connect jdbc:mysql://hadoop221:3306/test--username root --password admin --table uv_info --export-dir/user/hive/warehouse/uv/dt=2018-07-08

8、Hive中的查询

总体上来说,Hive中的查询跟关系型数据库中表的查询类似,其支持的SQL语句是SQL99标准的一个子集,因此,对于熟悉MySQL数据库的朋友,使用Hive来进行大数据分析,可以算得上是得心应手。但Hive毕竟是被设计成适合于大数据应用领域,使用Hive尽量按照分布式计算的一些特点来设计SQL,这和传统关系型数据库还是有区别的。因此,在使用Hive时,需要抛弃原有关系型数据库下开发的一些固有思维,可以参照下面的基本原则。

A**、Hive使用的基本原则**

尽量早地过滤数据,减少每个阶段的数据量,同时只选择需要使用到的字段;
*
尽量原子化操作,避免一个SQL包含复杂逻辑,可以使用中间表来完成复杂的逻辑;
*
对于join操作,小表要注意放在join的左边,否则会引起磁盘和内存的大量消耗;
*
如果union all的部分数目大于2,或者每个union部分数据量大,应该拆分成多个insert into语句,经过实践验证,执行实践可以提升50%;
*
启动一次MapReduce Job,尽可能多做一些事情,能够一个Job完成的事情,绝不要两个Job来做。通常来说,前面一个任务启动后,能够稍带一起做的事情就一起做了,以便后续的多个任务重用,与此紧密相连的是模型设计,好的模型非常重要;
*
写SQL语句之前要先了解数据本身的特点,如果有join,group操作的话,要注意是否会有数据倾斜,如果出现数据倾斜,应当合理配置相关参数;
*
尽量让服务器少做事情,走最优的路径,以资源消耗最少为目标;
*
注意小文件的问题,有两种处理方式,其一是使用Combinefileinputformat,将多个小文件打包作为一个整体的inputsplit,减少map任务数;其二是设置hive参数,将额外启动一个MapReduce Job打包小文件;
*
参数设置的调优等等。

B**、Hive支持的函数**

(1)数学函数

round
*
ceil
*
floor

(2)字符函数

lower
*
upper
*
length
*
concat
*
substr
*
trim
*
lpad
*
rpad

(3)收集函数

size

(4)日期函数

to_date
*
year
*
month
*
day
*
weekofyear
*
datediff
*
date_add
*
date_sub

(5)条件函数

if
*
coalesce
*
case... when...

(6)聚合函数

count
*
sum
*
min
*
max
*
avg

9**、Hive的Java编程**

通常情况下,我们都是利用CLI或者hive -e的方式来使用HQL执行查询、更新等操作。但是,Hive也提供客户端的实现,通过HiveServer或者HiveServer,客户端可以在不启动CLI的情况下对Hive中的数据进行操作,两者都允许远程客户端使用多种编程语言,如Java、Python等向Hive提交请求,取回结果。

HiveServer和HiveServer2有什么区别呢?HiveServer和HiveServer2都是基于Thrift,既然已经存在HiveServer,为什么还需要HiveServer2呢。因为HiveServer不能处理多于一个客户端的并发请求,这是由于HiveServer使用的Thrift接口所导致的限制,不能通过修改HiveServer的代码进行修正。因此,在Hive-0.11.0版本中重写了HiveServer代码得到了HiveServer2,进而解决了该问题。HiveServer2支持多客户端的并发和认证,为开放API客户端,如JDBC、ODBC等提供了更好的支持。

下面编写一个Java程序实例,来对Hive中的数据表emp进行查询,输出所有员工姓名和其薪水。下面的JDBCUtils类封装了JDBC相关的操作,比如注册JDBC驱动,获取数据库连接,增删改查操作以及释放数据库资源等。

面是操作Hive的Java主程序代码,从Hive中的emp表查询所有员工数据,然后输出他们的姓名和薪水。

这里需要注意,由于Hadoop中有权限检查的功能,直接运行该程序会报错:root is not allowed to impersonate anonymous,需要在Hadoop的核心配置文件core-site.xml中,增加如下内容,然后便可以正常运行该程序了。

<!--配置Hive任何用户都可以访问-->

<property>

<name>hadoop.proxyuser.root.hosts</name>

<value>/*</value>

</property>

<!--配置Hive任何组都可以访问-->

<property>

<name>hadoop.proxyuser.root.groups</name>

<value>/*</value>

</property>

10**、Hive的自定义函数**

虽然Hive内置了大量函数供用户进行使用,但在实际应用中,由于涉及到的业务纷繁复杂,单凭这些内置函数还是无法完全满足需求,因此,需要提供一种机制供用户开发自定义的函数。在Hive的CLI客户端运行命令showfunctions;可以查看Hive自带的所有内置函数;运行命令desc function upper;可以查看某个具体函数的用法;运行命令descfunction extended upper;可以查看某个具体函数的使用案例,如下图所示:

在Hive中如何开发自定义函数呢?一般而言,开发自定义的Hive函数的步骤分为如下几步:

自定义UDF extendsorg.apache.hadoop.hive.ql.exec.UDF;
*
需要实现evaluate函数,并且支持重载;
*
把程序打包放到目标机器上去;
*
进入hive客户端,添加jar包:hive>add jar jar路径;
*
创建临时函数:hive>createtemporary function自定义名称 AS ‘自定义UDF的全类名’;
*
执行HQL语句;
*
销毁临时函数:hive>droptemporary function 自定义名称;

下面以员工表为例,使用Java程序开发自定义的Hive函数,然后放到Hive客户端进行执行。下面的程序实例是自定义字符串拼接函数。

下面的程序是自定义员工薪水检查函数,实现的功能是:根据员工的薪水值,返回相对应的级别。

程序编写完成后,导出为myudf.jar文件,然后上传到主机Hadoop221的/root/temp目录下。然后,运行命令hive,登录到Hive的CLI客户端,运行命令add jar /root/temp/myudf.jar;部署自定义函数jar包。为使用方便,一般需要为自定义函数创建一个别名,依次运行如下两条命令,为自定函数MyConcatString和CheckSalaryGrade分别定义别名myconcat和mychecksalary:

createtemporary function myconcat as 'udf.MyConcatString';

createtemporary function mychecksalary as 'udf.CheckSalaryGrade';

运行结果如下图所示:

使用自定义函数myconcat对Hive中的数据表emp进行查询,如下图所示:

使用自定义函数mychecksalary对Hive中的数据表emp进行查询,如下图所示:

到这里为止,Hive的介绍就告一段落了,大家如果需要更深入了解Hive的原理及使用,可以再上网去找相关资料进行学习。

参考文献:

——《Hadoop权威指南》

——《SCSDN博客》

——《百度百科》

——《潭州大数据课程课件》

转自https://mp.weixin.qq.com/s/Jfm6Bsgez2ZuX-UxC6T6pw

相关文章

微信公众号

最新文章

更多