数据分析引擎Hive

涉及到的知识点:

  1. Hive的体系结构
  2. 安装和配置
  3. Hive的数据模型:内部表、分区表、外部表,桶表、视图
  4. Hive的查询(本质就是SQL)
  5. Hive的Java API(本质就是JDBC程序)
  6. Hive的自定义函数(UDF:user defined function。本质就是一个Java程序)

Hive的体系结构

Hive其实是构建在Hadoop上的数据仓库平台,为数据仓库管理提供了许多功能。其中最常用的功能就是翻译器,将我们的SQL语句,通过Hive引擎翻译称为MapReduce程序。不过需要注意的是Hive支持的是SQL99标准的一个子集,并不是全部支持。下面是Hive的体系结构图:

Hive的体系结构

在这里顺便提一下Hive和HDFS的对应关系(后面会说到):

​ Hive HDFS
表 –> 目录
分区 –> 目录
数据 –> 文件
桶 –> 文件

Hive的安装和配置

先安装并设置环境变量,后面再来说几种配置模式吧。

安装命令如下:

tar -zxvf apache-hive-2.3.0-bin.tar.gz -C ~/training/

安装完成之后就是环境变量的设置:

//编辑环境变量配置文件
vi ~/.bash_profile

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

PATH=$HIVE_HOME/bin:$PATH
export PATH


//使环境变量生效
source ~/.bash_profile

设置完成之后在命令行输入hive,然后按两下Tab键,产生如下结果说明配置成功:

Hive安装并配置环境变量成功的标志

接下来就是配置Hive的三种模式:

(1)嵌入模式

(2)本地模式

(3)远程模式

这三种模式都是通过配置文件: conf/hive-site.xml来实现的,需要注意的是hive-site.xml并不存在,我们需要自己新建。

嵌入模式

特点:

  • 不需要MySQL的支持,使用Hive的自带的数据库Derby
  • 局限:只支持一个连接

hive-site.xml具体配置如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<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>

<!-- value对应的目录要事先存在 -->
<property>
   <name>hive.metastore.warehouse.dir</name>
   <value>file:///root/training/apache-hive-2.3.0-bin/warehouse</value>
</property>

</configuration>

配置好hive-site.xml,我们需要初始化一下Derby数据库,我们在Hive的体系结构中提到,需要一个关系型数据库来保存Hive的元信息,在嵌入模式中使用自带的Derby即可,但是需要初始化,命令如下:

初始化Derby数据库
schematool -dbType derby -initSchema

初始化成功的标志如下:

嵌入模式初始化Derby成功标志

下面在命令行输入hive等待即可,如果顺利进入hive命令行模式说明嵌入式配置成功,结果如下:

嵌入模式配置成功标志

现在我们来创建一个table1,并插入一条数据,查看一下效果:
嵌入模式创建table1
嵌入模式插入数据

显然已经成功,需要注意的是表的这些信息就是保存在我们上面配置的那个warehouse目录下,并不是在HDFS,我们可以去查看一下:

嵌入模式数据保存结果

远程模式、本地模式

在进行远程模式、本地模式的配置之前,我们需要安装配置一下MySQL,具体步骤如下:

(1)解压压缩包

tar -xvf mysql-5.7.19-1.el7.x86_64.rpm-bundle.tar

(2)安装并配置MySQL:

//先删除linux默认安装的mysql驱动
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 start mysqld.service

    查看root用户的密码:cat /var/log/mysqld.log | grep password
    登陆:mysql -uroot -p
    修改密码:alter user 'root'@'localhost' identified by 'Welcome_1';

MySQL数据库的配置:
创建一个新的数据库:create database hive;
创建一个新的用户:
    create user 'hiveowner'@'%' identified by 'Welcome_1';
给该用户授权
    grant all on hive.* TO 'hiveowner'@'%'; 
    grant all on hive.* TO 'hiveowner'@'localhost' identified by 'Welcome_1';   

(3)安装MySQL的客户端 mysql front(免费的,百度到官网自己下即可)
新建链接,配置如下:

MySQL Front的配置

填写完之后点击OK,然后选中点击Open,就可见到如下页面:

mysql-hive数据库初始状态

好了,所有的MySQL相关的都已经安装配置完成了。下面我们进入Hive正式的配置:

(1)hive-site.xml文件(其实就是JDBC相关的配置):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
   <name>javax.jdo.option.ConnectionURL</name>
   <value>jdbc:mysql://localhost:3306/hive?useSSL=false</value>
</property>

<property>
   <name>javax.jdo.option.ConnectionDriverName</name>
   <value>com.mysql.jdbc.Driver</value>
</property>

<property>
   <name>javax.jdo.option.ConnectionUserName</name>
   <value>hiveowner</value>
</property>

<property>
   <name>javax.jdo.option.ConnectionPassword</name>
   <value>Welcome_1</value>
</property>

</configuration>

(2)将mysql的jar包放到lib目录下,注意一定要使用高版本的MySQL驱动(5.1.43以上的版本)

(3)初始化MySQL数据库

​(*)老版本:当第一次启动Hive的时候 自动进行初始化
(*)新版本:schematool -dbType mysql -initSchema
初始化成功日志如下:

初始化MySQL成功标志
现在我们再通过MySQL-Front看一下hive数据库:

mysql初始化之后自动生成的表(用来记录hive的元信息)

可以看见mysql生成了一系列的表用来保存hive的元信息。

到这里关系环境的配置就都完成了,后面我们开始介绍hive的一些常用知识点。

Hive的数据模型(注意:默认列的分隔符是tab键(制表符))

了解数据模型的目的是可以根据我们的需求结合各种数据模型,选择出最合适的来创建,方便我们后期工作的开展。

测试数据为员工表和部分表:

7499,ALLEN,SALESMAN,7698,1981/2/20,1600,300,30(员工表中的一条)

内部表:相当于MySQL的表

我们以上面员工表中一条为模板来创建内部表:

create table emp(
    empno int,
    ename string,
    job   string,
    mgr   int,
    hiredata string,
    sal   int,
    comm  int,
    deptno  int
);

创建结果如下:

创建内部表emp1

创建成功之后我们可以去看一下,在前面我们提到的关于hive的元信息,比如表名、列名等,我们通过MySQL-Front

数据库表元信息

这里写图片描述

在体系结构的最后我们提到了,Hive的表对应HDFS下的目录,我们现在可以通过web控制台去查看,地址ip:50070:

HDFS控制台:192.168.171.113:50070

HDFS控制台查看hive新建内部表目录

创建表完成之后,我们来导入数据,有以下两种方式:

  • insert(平常用的插入一条数据)

  • load(从某个HDFS的目录或者本地Linux的目录上,把数据导入Hive的表 本质ctrl+x)

    load data inpath ‘/input/emp.csv’ into table emp1; inpath表示导入HDFS的数据

    load data local inpath ‘/root/temp/emp.csv’ into table emp1; local inpath表示导入本地Linux的数据

我们执行load data inpath ‘/input/emp.csv’ into table emp1; 完成之后hdfs目录下/input下的emp.csv就不在了,因为被剪切走了,我们看一下:

执行load inpath之后的结果

既然已经load成功,我们就来查询一下:

导入emp表的查询结果(默认以tab键分割时查看)

这是什么鬼,难道我们那里操作失误了。答案是:我们确实失误了,因为所有Hive的数据模型,列的分隔符默认是Tab,而我们的emp.csv却是以,分割的,所以查询出来的数据异常,下面我们重新来创建表emp2,并制定分隔符为”,”,然后重新导入再来查看一下结果:

(1)创建新表emp2,并指定lie分隔符

create table emp2
(empno int,
ename string,
job string,
mgr int,
hiredate string,
sal int,
comm int,
deptno int)
row format delimited fields terminated by ',';  

(2)从linux本地导入数据

load data local inpath '/root/temp/emp.csv' into table emp2;  

(3)查询结果如下:

内部表二次操作

分区表

其实我们在MapperReduce的使用及高级功能的分区功能中已经提到过分区的概念,不了解的建议花点时间去看一下。Hive创建分区表的步骤如下:

(1)根据员工的部门号创建分区

create table emp_part
            (empno int,
            ename string,
            job string,
            mgr int,show
            hiredate string,
            sal int,
            comm int)
            partitioned by (deptno int)                 -->(部门号单独提取出来,用于作为分区条件)
            row format delimited fields terminated by ',';

(2)指明导入的数据的分区(通过子查询导入数据) —-> MapReduce程序

insert into table emp_part partition(deptno=10) select empno,ename,job,mgr,hiredate,sal,comm from emp2 where deptno=10;

insert into table emp_part partition(deptno=20) select empno,ename,job,mgr,hiredate,sal,comm from emp2 where deptno=20;

insert into table emp_part partition(deptno=30) select empno,ename,job,mgr,hiredate,sal,comm from emp2 where deptno=30;

我们在执行上面的插入数据时发现,每次执行一条语句默认会打印出很多日志,此时不利于我们的操作和观察,我们可以开启hive的静默模式,操作如下:

//先离开hive命令行模式
quit;
//重新启动
hive -S         -->   报错不会受到影响

上两张图对比一下开启前后的效果:

hive非静默模式

hive开启静默模式之后

很明显,感觉爽多了。我们继续上面的正题。现在我们分区表已经初始化完成,我们分别通过内部表(普通表)和分区表来查询一下deptno=10的数据:

内部表、分区表查询deptno=10数据

结果是一样的,那么分区表存在的意义是什么呢?答案是效率更高,我们通过查询SQL的执行计划来作一下对比:

[内部表(普通表)执行计划

分区表执行计划

前面为内部表(普通表),后面为分区表,分区表明显查询数据的大小小了很多,在效率上有显著的提升。这就是分区表的用处。

执行计划如何看?从下往上,从右往左

视图

视图其实是一个虚表,具有以下的特点:

  • 视图不存数据,依赖于其它的表,被视图依赖的表叫基表
  • 操作视图跟操作表 一样。原因其实就是第一条,它本身不存数据,而是依赖于其它基表
  • 视图并不可以提高查询的效率,它的作用是简化复杂的查询
  • 物化视图(可以缓存数据)–> 可以自己去研究一下

举例查询员工信息:部门名称 员工姓名

(1)创建部门表并导入数据

create table dept
            (deptno int,
            dname string,
            loc string)
            row format delimited fields terminated by ',';

然后导入数据:

load data inpath ‘/input/dept.csv’ into table dept;(linux本地导入)

(2)创建视图

create view myview
as  
select dept.dname,emp2.ename
from emp2,dept
where emp2.deptno=dept.deptno;

(3)查询结果

select * from myview;

hive视图多表查询结果

外部表

外部表和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异,它是指向HDFS上已经存在的数据,可以创建Partition。除此之外还具有以下特点:

  • 只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据建立一个链接。当删除一个外部表时,仅删除该链接

介绍完定义,我们下面来作一波操作演示一下外部表的使用:

(1)创建两个测试数据(linux本地)

//student01.txt
vi student01.txt
1,Tom,21
2,Jane,22

//student02.txt
3,Anna,23

(2)在HDFS上创建student目录,并把上面的测试数据上传上去

//在HDFS上创建student目录
hdfs dfs -mkdir /students

//上传数据到HDFS
hdfs dfs -put student01.txt /students
hdfs dfs -put student02.txt /students

(3)创建外部表,关联HDFS上的student目录

create external table students_ext              --> 关键字external用于标识这是一个外部表
(sid int,sname string,age int)
row format delimited fields terminated by ','
location '/students';                          --> 关键字location用于指定HDFS上的目录

(4)hive查看结果:

Hive初始化外部表查询结果

(5)在Linux本地新建student03.txt,添加一条数据,然后上传到HDFS /students目录下,再次查看Hive:

Hive外部表插入新数据到HDFS新查询结果

桶表:桶是一个文件

桶表是对数据进行哈希取值,然后放到不同文件中存储。其思想和我们前面的文章MapperReduce的使用及高级功能 里面提到的Hash分区是一样的,如果不了解的可以去看一下。

下面以创建一个桶表为例:

(1)创建桶表

create table emp_bucket
            (empno int,
            ename string,
            job string,
            mgr int,
            hiredate string,
            sal int,
            comm int,
            deptno int)
            clustered by (job) into 4 buckets               --> 关键字clustered标识桶表
            row format delimited fields terminated by ',';  

(2)设置环境变量打开桶表,否则无效

set hive.enforce.bucketing = true;

(3)通过子查询插入数据

insert into emp_bucket select * from emp2;

(4)查询结果

桶表查询结果

Hive的查询

Hive的查询本质就是SQL,通过输入sql语句,将其转化为MapReduce操作(简单的并不会转换),最终得到结果。我们列几个示例介绍一下即可。

(1)查询所有的员工信息

select * from emp2;

(2)查询员工信息:员工号 姓名 薪水

select empno,ename,sal from emp2;

(3)多表查询:部门名称 员工姓名

select dept.dname,emp2.ename
    from emp2,dept
    where emp2.deptno=dept.deptno;  

(4)子查询hive只支持:from和where子句中的子查询

select * from emp2
where emp2.deptno in (select deptno from dept where dname='SALES');

补充:Oracle数据库中可以使用子查询的:from、where、select、having后面
不能使用子查询:group by

(5)条件函数: case …. when ….(Oracle中叫条件表达式)
是标准的SQL语句
实际上就是在SQL中实现一个if else 逻辑

​ 举例:做报表,根据职位给员工涨工资
PRESIDENT 1000
MANAGER 800
其他 400

把涨前、涨后的薪水显示出来

select empno,ename,job,sal,
    case job when 'PRESIDENT' then sal+1000
            when 'MANAGER' then sal+800
            else sal+400
    end 
    from emp2;    

补充:Oracle中,条件表达式还有一种方式:decode函数 —> Oracle自己的语法

通过JDBC操作Hive

在通过JDBC操作Hive时,有以下几点需要注意:

(1)jar包,把hive下的jar包拷贝一份进入项目,具体目录如下:

/root/training/apache-hive-2.3.0-bin/lib (只要jar包即可)

(2)启动HiveServer2(这个我们在最开始介绍Hive的体系结构的时候已经说明),命令如下:

hiveserver2 &(不是hive命令行模式,而是正常linux命令行模式)

(3)修改hadoop的配置文件 – core-site.xml,否则会报以下错误:

Caused by: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException:User: root is not allowed to impersonate anonymous

具体配置如下:

<property>
  <name>hadoop.proxyuser.root.hosts</name>
  <value>*</value>
</property>

<property>
  <name>hadoop.proxyuser.root.groups</name>
  <value>*</value>
</property>

配置完成之后将hadoop重启,然后运行代码,结果如下:

hive JDBC实现范例结果

下面把代码贴上,需要的直接复制,黏贴即可:

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * function:工具类
 * 1、获取链接
 * 2、释放资源:Connection、Statement、ResultSet
 * author by cpMark
 * create on 2018/5/11.
 */

public class JDBCUtils {

    /**
     *  Hive的驱动(固定写法)
     */
    private static String mDriver = "org.apache.hive.jdbc.HiveDriver";
    //Oracle数据库: oracle.jdbc.OracleDriver

    /**
     * Hive的URL地址
     */
    private static String mUrl = "jdbc:hive2://192.168.171.113:10000/default";

    /**
     * 注册数据库的驱动
     */
    static{
        try{
            Class.forName(mDriver);
        }catch(Exception ex){
            throw new ExceptionInInitializerError(ex);
        }
    }

    /**
     * 获取Hive数据库的链接
     * @return
     */
    public static Connection getConnection(){
        try{
            return DriverManager.getConnection(mUrl);
        }catch(Exception ex){
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * 释放资源
     * @param conn
     * @param st
     * @param rs
     */
    public static void release(Connection conn, Statement st, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                rs = null;
            }
        }
        if(st != null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                st = null;
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                conn = null;
            }
        }
    }


}
package jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * function:
 * author by cpMark
 * create on 2018/5/11.
 */

public class HiveMain {

    public static void main(String[] args){
        //查询员工信息
        String sql = "select * from emp2";

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JDBCUtils.getConnection();

            //得到SQL的运行环境
            st = conn.createStatement();

            //运行SQL
            rs = st.executeQuery(sql);
            while (rs.next()){
                //姓名和薪水
                //注意:好像不能通过列的索引号获取。只能通过列名来获取
                String ename = rs.getString("ename");
                double sal = rs.getDouble("sal");
                System.out.println(ename+"\t"+sal);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.release(conn,st,rs);
        }
    }

}

Hive的自定义函数

Hive的自定义函数(UDF:user defined function):本质就是一个Java程序,只是封装了我们自己的业务逻辑。下面我们以一个例子来演示如何使用自定义函数 – concat函数,拼接字符串:

package udf;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
 * function:拼接字符串的功能
 * author by cpMark
 * create on 2018/5/12.
 */

public class MyConcatString extends UDF {

    /**
     *  定义的方法,方法名必须叫:evaluate
     */
    public String evaluate(String a,String b){
        return a + "***" + b;
    }

}

导出成jar包,并部署(部署命令在下图),结果如下:

自定义Hive函数

到此为止关于Hive的所有知识点都已经介绍完了。下一篇数据分析引擎Pig,敬请期待!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值