什么是Hive
定义了一种类SQL语言HiveQL。可以看成是仍SQL到Map-Reduce的映射器
Hive 将元数据存储在数据库中(metastore),目前只支持 mysql、derby。Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等。
Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成(包含 * 的查询,比如 select * from table 不会生成 MapRedcue 任务)
1、Hive是一个翻译器,SQL ---> Hive引擎 ---> MR程序
2、Hive是构建在HDFS上的一个数据仓库(Data Warehouse)
Hive HDFS
表 目录
分区 目录
数据 文件
桶 文件
Hive的体系结构
安装和配置
1解压:jiaytar -zxvf apache-hive-2.3.0-bin.tar.gz -C ~/training/
2设置环境变量
HIVE_HOME=/root/training/apache-hive-2.3.0-bin
export HIVE_HOME
PATH=$HIVE_HOME/bin:$PATH
export PATH
3核心配置文件: conf/hive-site.xml
嵌入模式 不需要MySQL的支持,使用Hive的自带的数据库Derby 局限:只支持一个连接
<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>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>file:///root/training/apache-hive-2.3.0-bin/warehouse</value>
</property>
</configuration>
初始化Derby数据库:
which schematool 查找命令地址
schematool -dbType derby -initSchema
启动 : hive
远程模式:需要MySQL
<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>
将mysql的jar包放到lib目录下 一定要使用高版本的MySQL驱动(5.1.43以上的版本)
初始化MySQL
老版本:当第一次启动HIve的时候 自动进行初始化
新版本:schematool -dbType mysql -initSchema
Hive的数据类型
- 基本数据类型
- tinyint/smallint/int/bigint:整数类型
- float/double:浮点数类型
- boolean:布尔类型
- string:字符串类型
- 复杂数据类型
- Array:数组类型,由一系列相同数据类型的元素组成
- Map:集合类型,包含key->value键值对,可以通过key来访问元素。
- Struct:结构类型,可以包含不同数据类型的元素。这些元素可以通过”点语法”的方式来得到所需要的元素
- 时间类型
- Date:从Hive0.12.0开始支持
- Timestamp:从Hive0.8.0开始支持
Hive的数据模型
Hive的数据存储
- 基于HDFS
- 没有专门的数据存储格式
- 存储结构主要包括:数据库、文件、表、视图
- 可以直接加载文本文件(.txt文件)
- 创建表时,指定Hive数据的列分隔符与行分隔符
注意:默认:列的分隔符是tab键(制表符),建表时需要指定分隔符
测试数据:员工表和部门表
7654,MARTIN,SALESMAN,7698,1981/9/28,1250,1400,30
内部表
- 与数据库中的 Table 在概念上是类似
- 删除表时,元数据与数据都会被删除
- 所有的 Table 数据(不包括 External Table)都保存在这个目录中
- 每一个 Table 在 Hive 中都有一个相应的目录存储数据
create table emp
(empno int,
ename string,
job string,
mgr int,
hiredate string,
sal int,
comm int,
deptno int) row format delimited fields terminated by ',';
--按照条件查询结果存储到新表
create table if not exists emp_2 as select * from emp where ename ='tongla';
--查询结果导出到本地
insert overwrite local directory '/root/datas/yangmi.txt' select * from emp where ename ='tongla';
导入数据
load data inpath '/scott/emp.csv' into table emp; --导入HDFS的数据
load data inpath '/scott/emp.csv' overwrite into table emp; --导入HDFS的数据 并覆盖原数据
load data local inpath '/root/temp/*****' into table emp; --导入本地Linux的数据
分区表: 可以提高查询的效率的----> 通过查看SQL的执行计划
- Partition 对应于数据库的 Partition 列的密集索引
- 在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中
create table emp_part
(empno int,
ename string,
job string,
mgr int,
hiredate string,
sal int,
comm int)
partitioned by (deptno int)
row format delimited fields terminated by ',';
--添加分区
alter table emp_part add partition(deptno ='1113');
--查询表结构
desc formatted emp_part;
--修改表名
alter table emp_part rename to new_table_name;
--添加列
alter table emp_part add columns(desc string);
--更新列
alter table emp_part change column desc desccc int;
--替换
alter table emp_part replace column(desccc int);
指明导入的数据的分区(通过子查询导入数据) ----> MapReduce程序
insert into table emp_part partition(deptno=10) select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=10;
insert into table emp_part partition(deptno=20) select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=20;
insert into table emp_part partition(deptno=30) select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=30;
外部表
- 指向已经在 HDFS 中存在的数据,可以创建 Partition
- 它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异
- 外部表 只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据建立一个链接。当删除一个外部表时,仅删除该链接
create external table students_ext
(sid int,sname string,age int)
row format delimited fields terminated by ','
location '/students1';
桶表
- 桶表是对数据进行哈希取值,然后放到不同文件中存储。
- 需要设置环境变量:set hive.enforce.bucketing = true;
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
row format delimited fields terminated by ',';
通过子查询插入数据
insert into emp_bucket select * from emp1;
视图(View)
- 视图是一种虚表,是一个逻辑概念;可以跨越多张表
- 视图建立在已有表的基础上, 视图赖以建立的这些表称为基表
- 视图可以简化复杂的查询
create view myview
as
select dept.dname,emp1.ename
from emp1,dept
where emp1.deptno=dept.deptno;
使用sqoop导入关系型数据库中的数据
将关系型数据的表结构复制到hive中
sqoop create-hive-table --connect jdbc:mysql://localhost:3306/test --table username --username root --password 123456 --hive-table test
其中 --table username为mysql中的数据库test中的表 --hive-table test 为hive中新建的表名称
从关系数据库导入文件到hive中
sqoop import --connect jdbc:mysql://localhost:3306/test --username root --password mysql-password --table t1 --hive-import
将hive中的表数据导入到mysql中
sqoop export --connect jdbc:mysql://localhost:3306/test --username root --password admin --table uv_info --export-dir /user/hive/warehouse/uv/dt=2011-08-03
Hive的查询
1、查询所有的员工信息
select * from emp1;
2、查询员工信息:员工号 姓名 薪水
select empno,ename,sal from emp1;
3、多表查询 部门名称 员工姓名
select dept.dname,emp1.ename
from emp1,dept
where emp1.deptno=dept.deptno;
4、子查询:
hive只支持:from和where子句中的子查询
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 emp1;
Hive的Java API:本质就是JDBC程序
- 首先启动Hive远程服务:hiveserver2 &
- 需要Hive lib目录下的jar包
如出现错误 : User: root is not allowed to impersonate anonymous
修改hadoop 配置文件 etc/hadoop/core-site.xml,加入如下配置项
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
*
* 工具类:
* 1、获取数据库Hive链接
* 2、释放资源
*/
public class JDBCUtils {
//Hive数据库的驱动
private static String driver = "org.apache.hive.jdbc.HiveDriver";
//Hive位置
private static String url = "jdbc:hive2://192.168.157.111:10000/default";
//注册驱动
static{
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new ExceptionInInitializerError(e);
}
}
//获取链接
public static Connection getConnection(){
try {
return DriverManager.getConnection(url);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
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;
}
}
}
}
public class TestMain {
public static void main(String[] args) {
String sql = "select * from mytest1";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
//获取链接
conn = JDBCUtils.getConnection();
//得到运行环境
st = conn.createStatement();
//运行SQL
rs = st.executeQuery(sql);
//处理
while(rs.next()){
//取员工姓名, 不能通过列名来取,通过序号
int id = rs.getInt("tid");
String name = rs.getString("tname");
System.out.println(id+"\t"+name);
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
//释放资源
JDBCUtils.release(conn, st, rs);
}
}
}
Hive的自定义函数
1Hive的自定义函数(UDF): User Defined Function
可以直接应用于select语句,对查询结构做格式化处理后,再输出内容
2Hive自定义函数的实现细节
自定义UDF需要继承org.apache.hadoop.hive.ql.UDF
需要实现evaluate函数,evaluate函数支持重载
3Hive自定义函数的部署
把程序打包放到目标机器上去
进入hive客户端,添加jar包:
hive> add jar /root/temp/udf.jar;
4创建临时函数:
create temporary function myconcat as 'udf.MyConcatString';
create temporary function checksal as 'udf.CheckSalaryGrade';
5Hive自定义函数的调用
查询HQL语句:
select myconcat(ename,job) from emp;
select ename,sal, checksal (sal) from emp;
销毁临时函数:
hive> DROP TEMPORARY FUNCTION checksalary;
Hive优化
压缩
开启Map阶段输出压缩
开启输出压缩功能:set hive.exec.compress.intermediate=true;
开启map输出压缩功能:set mapreduce.map.output.compress=true;
设置压缩方式:
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
开启reduce输出端压缩:
开启最终输出压缩功能: set hive.exec.compress.output=true;
开启最终数据压缩功能: set mapreduce.output.fileoutputformat.compress=true;
设置压缩方式: set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
设置块压缩:set mapreduce.output.fileoutputformat.compress.type=BLOCK;
存储:
Hive存储格式:TextFile/SequenceFile/orc/Parquet
orc:Index Data/row Data/stripe Footer
压缩比:
orc > parquet > textFile
查询速度:
orc > textFile
Group by优化:
分组:mr程序,map阶段把相同key的数据分发给一个reduce,一个key的量很大。
解决方案:
在map端进行聚合(combiner) set hive.map.aggr=true;
设置负载均衡 set hive.groupby.skewindata=true;
数据倾斜:
合理避免数据倾斜
合理设置map数
合并小文件
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
合理设置reduce数
解决数据倾斜
在map端进行聚合(combiner) set hive.map.aggr=true;
设置负载均衡 set hive.groupby.skewindata=true;
JVM重用 mapred-site.xml
mapreduce.job.jvm.numtasks 10~20