Hive

Hive 核心概念介绍及入门

Posted by leone on 2017-08-15

Hive

Hive 核心概念介绍及入门

什么是 Hive

hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

最初,Hive是由Facebook开发,后来由Apache软件基金会开发,并作为进一步将它作为名义下Apache Hive为一个开源项目。Hive 没有专门的数据格式。 Hive 可以很好的工作在 Thrift 之上,控制分隔符,也允许用户指定数据格式。Hive不适用于在线事务处理。 它最适用于传统的数据仓库任务。

Hive的的优点及应用场景

  • Hive可以自由的扩展集群的规模,一般情况下不需要重启服务。

  • Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。

  • 良好的容错性,节点出现问题SQL仍可完成执行。

  • 操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手);

  • 避免了去写MapReduce,减少开发人员的学习成本;

  • 统一的元数据管理,可与impala/spark等共享元数据;

  • 易扩展(HDFS+MapReduce:可以扩展集群规模;支持自定义函数);

  • 数据的离线处理;比如:日志分析,海量结构化数据离线分析;

  • Hive的执行延迟比较高,因此hive常用于数据分析的,对实时性要求 不高的场合;

  • Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执 行延迟比较高;

数据仓库概念

数据仓库(Data Warehouse)是一个面向主题的(Subject Oriented)、集成的(Integrated)、相对稳定的(Non-Volatile)、反应历史变化(Time Variant)的数据集合,用于支持管理决策。数据仓库体系结构通常含四个层次:数据源、数据存储和管理、数据服务、数据应用。

  • 数据源:是数据仓库的数据来源,含外部数据、现有业务系统和文档资料等;

  • 数据集成:完成数据的抽取、清洗、转换和加载任务,数据源中的数据采用ETL(Extract-Transform-Load)工具以固定的周期加载到数据仓库中。

  • 数据存储和管理:此层次主要涉及对数据的存储和管理,含数据仓库、数据集市、数据仓库检测、运行与维护工具和元数据管理等。

  • 数据服务:为前端和应用提供数据服务,可直接从数据仓库中获取数据供前端应用使用,也可通过OLAP(OnLine Analytical Processing,联机分析处理)服务器为前端应用提供负责的数据服务。

  • 数据应用:此层次直接面向用户,含数据查询工具、自由报表工具、数据分析工具、数据挖掘工具和各类应用系统。

Hive中表的分类

内部表:什么是内部表需要对比外部表来看删表时数据和表一起删除。

外部表:数据已经存在于HDFS,外部表只是走一个过程,加载数据和创建表同时完成,不会移动到数据仓库目录中,仅仅是和数据建立了一个连接,删表数据不会删除数据。

分区表:在Hive Select查询中,一般会扫描整个表内容,会消耗很多时间做没必要的工作。 分区表指的是在创建表时,指定partition的分区空间。扫描时可以只扫描某一个分区的数据,分区表存储时分局所设立的分区分别存储数据(分区字段就是一个文件夹的标识)分区表可以是内部表也可以是外部表。

分桶表:对于每一个表(table)或者分区,Hive可以进一步组织成桶,也就是说捅是更为细粒度的数据范困划分。分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储,一个文件对应一个桶由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中

Hive架构体系

  • 用户接口主要有三个:CLI,Client 和 WUI。其中最常用的是CLI,Cli启动的时候,会同时启动一个Hive副本。Client是Hive的客户端,用户连接至Hive Server。在启动 Client模式的时候,需要指出Hive Server所在节点,并且在该节点启动Hive Server。 WUI是通过浏览器访问Hive。

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

  • 解释器、编译器、优化器完成HQL查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS中,并在随后有MapReduce调用执行。

  • Hive的数据存储在HDFS中,大部分的查询计算由MapReduce完成(包含*的查询,比如select * from table不会生成MapRedcue任务),Hive将元数据存储在RDBMS中

Hive核心组件

Driver

实现了session handler,在JDBC/ODBC接口上实现了执行和获取信息的API。

Compiler

该组件用于对不同的查询表达式做解析查询,语义分析,最终会根据从metastore中查询到的表和分区元数据生成一个execution plain。

Execution Egine

该组件会执行由compiler创建的execution。其中plan从数据结构上来看,是一个DAG,该组件会管理plan的不同stage与组件中执行这些plan之间的依赖。

Metastore

Hive的metastore组件是hive元数据集中存放地。该组件存储了包括变量表中列和列类型等结构化的信息以及数据仓库中的分区信息(包括列和列类型信息,读写数据时必要的序列化和反序列化信息,数据被存储在HDFS文件中的位置)。Metastore组件包括两个部分:metastore services和Meta storage database。

hive的特点

  • 通过SQL轻松访问数据的工具,从而实现数据仓库任务(如提取/转换/加载(ETL),报告和数据分析)。

  • 一种对各种数据格式施加结构的机制

  • 访问直接存储在Apache HDFS或其他数据存储系统(如Apache HBase)中的文件

  • 通过Apache Tez,Apache Spark或MapReduce执行查询

  • 程序语言与HPL-SQL

  • 通过Hive LLAP,Apache YARN和Apache Slider进行亚秒级查询检索。

Hive与Hadoop生态系统中其他组件的关系

  • Hive依赖于HDFS存储数据,依赖MR处理数据;

  • Pig可作为Hive的替代工具,是一种数据流语言和运行环境,适合用于在Hadoop平台上查询半结构化数据集,用于与ETL过程的一部分,即将外部数据装载到Hadoop集群中,转换为用户需要的数据格式;

  • HBase是一个面向列的、分布式可伸缩的数据库,可提供数据的实时访问功能,而Hive只能处理静态数据,主要是BI报表数据,Hive的初衷是为减少复杂MR应用程序的编写工作,HBase则是为了实现对数据的实时访问

hive 的数据类型

数据类型 长度 备注
Tinyint 1字节的有符号整数 -128~127
SmallInt 1个字节的有符号整数 -32768~32767
Int 4个字节的有符号整数 -2147483648 ~ 2147483647
BigInt 8个字节的有符号整数
Boolean 布尔类型,true或者false true、false
Float 单精度浮点数
Double 双精度浮点数
String 字符串
TimeStamp 整数 支持Unix timestamp,可以达到纳秒精度
Binary 字节数组
Date 日期 0000-01-01 ~ 9999-12-31,常用String代替

hive 安装和客户端操作

hive的安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 首先需要安装hadoop、mysql[参见](http://wwww.google.com)

# 下载
$ wget http://mirrors.shu.edu.cn/apache/hive/hive-2.3.4/apache-hive-2.3.4-bin.tar.gz

# 解压
$ tar -zxvf apache-hive-2.3.4-bin.tar.gz

# 添加hive-env.sh
$ cp $HIVE_HOME/conf/hive-env.sh.template hive-env.sh

# 新增两行
export HADOOP_HOME=$HADOOP_HOME
export HIVE_CONF_DIR=$HIVE_HOME/conf

# 新增hive-site.xml
$ vi hive-site.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration>

<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://ip:3306/hive?createDatabaseIfNotExist=true&amp;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>root</value>
</property>

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

<!-- 配置hive的数据目录 -->
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/hive-2.3.4</value>
</property>

</configuration>

# 拷贝mysql的驱动到$HIVE_HOME/lib下

# 初始化hive
$ $HIVE_HOME/bin/schematool -dbType mysql -initSchema

# 检测hive是否安装成功
$HIVE_HOME/bin/hive

# 启动hive服务
$ $HIVE_HOME/bin/hiveserver2


# 客户端连接hive

# 第一种连接 hivesever 的方式
$ $HIVE_HOME/bin/beeline

# 输入用户名:你主机的用户 密码:直接输入回车
!connect jdbc:hive2://node-1:10000

# 第二种连接 hiveServer 的方式
$ $HIVE_HOME/bin/beeline -u jdbc:hive2://node-1:10000 -n root

bin/beeline -u jdbc:hive2://node-1:10000/default;auth=noSasl

hive 命令行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# hive的sql操作和mysql差不多

# 查看所有数据库
> show databases;

# 创建数据库
> create database db1;

# 删除数据库
> drop database db1;

# 使用指定数据
> use db1;

# 查看数据库中的所有表
> show tables;

# 删除表
> drop table t_user;

# 创内部建表
> create table t_user(id int, name string, sex string, age int,
department string)row format delimited fields terminated by ',';

# 插入数据
> insert into t_user values(1,"老王","男",28,"IS")

# 查询表中的数据
> select * from t_user limit 1;

# 创建外部表
> create table t_user(id int, name string, sex string, age int, department string)
row format delimited fields terminated by',' location '/app-log/data';

# 创建分区表
> create external table t_user(id int, name string, sex string,
age int, department string) partitioned by (create_time string)
row format delimited fields terminated by ',' location '/app-log';

# 分区表从本地文件系统加载数据
> load data local inpath '/root/2018-12-02.log' into table t_user partition(create_time=20181202);

# insert单条插入的方式往分区表中插入数据
> insert into t_user partition (create_time="20181201") values(2,"老王","男",18,"IS")

# 删除Hive分区表中的分区
> alter table t_user drop partition(create_time="20181203");

# 查询指定分区表中的数据
> select count(1) from t_user where day='2019-03-27' and hour = 11;

# 创建临时表TEMPORARY代表这是一个临时表
> create temporary table t_temp(id int,name string);

# 创建多级分区表
> create table t_user2(id int, username string, age int)partitioned
by (day string, hour int) row fromat delimited fields terminated by ',';

# 多级分区表插入数据
> insert into t_user2 partition(day='2019-03-27', hour=1) values(1,"leone",12),(2,"tom",18),(3,"jandy",19);

# 多级分区表添加分区并加载数据
> alter table t_user add partition(day='2019-03-27', hour=9) location '/data/csv/2019-03-27/09';

# 添加分区
> alter table t_user2 add partition (day='2019-03-29', hour=10);

# 分桶表 (开启hive的分桶表开关set hive.enforce.bucketing=true;)
> create table t_user3(id int, username string, age int) clustered by(age)
into 4 buckets row format delimited fields terminated by ',';

# 分桶表插入数据只可以使用insert
> insert into t_user3 values(1, "james", 19),(2, "andy", 35),(3, "tom", 18),
(4, "jerry", 23),(5, "leone", 25),(6, "kobe", 45),(7, "justin", 29),(8, "colin", 13);

hive java 客户端CRUD操作

  • pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<dependencies>

<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>2.3.4</version>
</dependency>

<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.3.4</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
  • HiveClientTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

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

/**
* <p> jdbc连接hive
*
* @author leone
* @since 2018-06-17
**/
public class HiveClientTest {

/**
* 1,123.25.51.81,https://www.google.com,2019-01-21
* 2,123.25.51.82,https://www.youku.com,2019-01-22
* 3,123.25.51.83,https://www.taobao.com,2019-01-23
* 4,123.25.51.84,https://www.baidu.com,2019-01-24
* 5,123.25.51.85,https://www.jd.com,2019-01-26
* 6,123.25.51.86,https://www.tianmao.com,2019-01-27
*/

private Connection connection;

private Statement statement;

@Before
public void init() throws Exception {
Class.forName("org.apache.hive.jdbc.HiveDriver");
connection = DriverManager.getConnection("jdbc:hive2://node-1:10000/db1", "root", "");
statement = connection.createStatement();
}

/**
* 查询表数据
*
* @throws Exception
*/
@Test
public void selectTest() throws Exception {
ResultSet result = statement.executeQuery("select * from t_log");
System.out.println("-----------------------------------------------------");
System.out.println("id\tip\turl\ttime");
System.out.println("-----------------------------------------------------");
while (result.next()) {
int id = result.getInt(1);
String ip = result.getString(2);
String url = result.getString(3);
String time = result.getString(4);
System.out.println("|" + id + "\t" + ip + "\t" + url + "\t" + time + "|");
}
System.out.println("-----------------------------------------------------");
}


/**
* 创建表
*
* @throws Exception
*/
@Test
public void dropTableTest() throws Exception {
String sql = "drop table if exists t_log";
boolean flag = statement.execute(sql);
System.out.println("running sql:" + sql + (flag ? " " : "failed success"));
}


/**
* 删除数据库
*
* @throws Exception
*/
@Test
public void dropDatabaseTest() throws Exception {
String sql = "drop database if exists db1";
boolean flag = statement.execute(sql);
System.out.println("running sql:" + sql + (flag ? " " : "failed success"));
}


/**
* 创建表
*
* @throws Exception
*/
@Test
public void createTableTest() throws Exception {
String sql = "create table t_log(id int, ip string, url string, time string)" +
" row format delimited fields terminated by ','";
boolean flag = statement.execute(sql);
System.out.println("running sql:" + sql + (flag ? " " : "failed success"));
}


/**
* 查询所有表
*
* @throws Exception
*/
@Test
public void showTablesTest() throws Exception {
ResultSet resultSet = statement.executeQuery("show tables");
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
}


/**
* 加载数据
*
* @throws Exception
*/
@Test
public void loadDataTest() throws Exception {
String filePath = "/root/app.log";

String sql = "load data local inpath '" + filePath + "' overwrite into table t_log";
boolean flag = statement.execute(sql);
System.out.println("running sql:" + sql + (flag ? " " : "failed success"));
}


/**
* 统计查询(会运行 mapReduce 作业)
*
* @throws Exception
*/
@Test
public void countDataTest() throws Exception {
String sql = "select count(1) from t_log";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getInt(1));
}
boolean flag = statement.execute(sql);
System.out.println("running sql:" + sql + (flag ? " " : "failed success"));
}
}