Hive学习笔记
一、简介
Hive 是一个构建在 Hadoop 之上的数据仓库,它可以将结构化的数据文件映射成表,并提供类 SQL 查询功能,用于查询的 SQL 语句会被转化为 MapReduce 作业,然后提交到 Hadoop 上运行。
特点:
- 简单、容易上手 (提供了类似 sql 的查询语言 hql),使得精通 sql 但是不了解 Java 编程的人也能很好地进行大数据分析;
- 灵活性高,可以自定义用户函数 (UDF) 和存储格式;
- 为超大的数据集设计的计算和存储能力,集群扩展容易;
- 统一的元数据管理,可与 presto/impala/sparksql 等共享数据;
- 执行延迟高,不适合做数据的实时处理,但适合做海量数据的离线处理;
- 不是关系型数据库。
二、安装配置
下载解压hive包(这里我是3的版本)
Code$tar -zxvf apache-hive-3.1.2-bin.tar.gz
$mv apache-hive-3.1.2-bin /soft/
$ln -s apache-hive-3.1.2-bin hive配置环境变量
Code# Hive
export HIVE_HOME=/soft/hive
export PATH=$PATH:$HIVE_HOME/bin
# 配置生效
$source /etc/profile复制mysql驱动程序到hive的lib目录下
Code$cp mysql-connector-java-5.1.38.jar /soft/hive/lib/
配置hive-env.sh
在hive下的conf目录下,找到hive-env.sh.template,并复制一份重命名为hive-env.sh
Code$cp hive-env.sh.template hive-env.sh
编辑hive-env.sh,修改配置:
Code# Hadoop安装目录
HADOOP_HOME=/soft/hadoop
# HIVE配置文件目录
export HIVE_CONF_DIR=/soft/hive/conf
# HIVE库文件目录
export HIVE_AUX_JARS_PATH=/soft/hive/lib配置hive-site.xml
在hive下的conf目录下,找到hive-default.xml.template,并复制一份重命名为hive-site.xml
Code$cp hive-default.xml.template hive-site.xml
然后对如下内容进行修改:
xml<!-- 数据库的账户、密码 -->
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>Username to use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
<description>password to use against metastore database</description>
</property>
<!-- 连接的MYSQL数据库,IP是我自己的本机WIN10。记得去创一个hive的数据库 -->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://192.168.203.1:3306/hive?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>
<!-- 设置目录 -->
<property>
<name>hive.exec.local.scratchdir</name>
<value>/home/wbw/hive</value>
<description>Local scratch space for Hive jobs</description>
</property>
<!-- 设置下载资源目录 -->
<property>
<name>hive.downloaded.resources.dir</name>
<value>/home/wbw/hive/downloads</value>
<description>Temporary local directory for added resources in the remote file system.</description>
</property>
<!-- 设置查询日志目录 -->
<property>
<name>hive.querylog.location</name>
<value>/home/wbw/hive/querylog</value>
<description>Location of Hive run time structured log file</description>
</property>
<!-- 日志 -->
<property>
<name>hive.server2.logging.operation.log.location</name>
<value>/home/wbw/hive/server2_log</value>
<description>Top level directory where operation logs are stored if logging functionality is enabled</description>
</property>
<!-- 提示信息 -->
<property>
<name>hive.cli.print.header</name>
<value>true</value>
<description>Whether to print the names of the columns in query output.</description>
</property>
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
<description>Whether to include the current database in the Hive prompt.</description>
</property>创建hive数据库
sqlcreate database hive;
初始化hive的元数据(表结构)到mysql中
Code$schematool -dbType mysql -initSchema
这时候报错:
发现是hive-site.xml第3215行错误,定位到错误的地方:
Codevi hive-site.xml +3215
发现是注释 description 中的内容,有一个for的东西,将后面的&…;删除即可。然后重新执行初始化命令。
最后查看MYSQL发现多了很多表。
启动Hive(要先启动HDFS)
Code$hive
注意事项(别人写的,如果有问题可以试试)
hive-site.xml中 mysql的驱动名称为com.mysql.cj.jdbc.Driver
xml文档中javax.jdo.option.ConnectionURL中&要用&替代,一定要指定字符集,时区
Codejdbc:mysql://127.0.0.1:3306/hive?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
我已经提前对数据库的root用户进行授权
三、HiveQL命令
在hive中的命令和MySQL基本上是一致的。有一点要注意, 数据是存在HDFS上的,HIVE只是用来做一个映射,他的元数据是放在MySQL上的(自带的不好用只能单线程不用)。
3.1 基本命令
查看版本
$hive --version |
查看帮助
$hive --help |
启动HIVE
$hive |
相当于开启了一个服务hive –service cli。但是不能并行。
退出HIVE
hive >exit; |
3.2 数据库相关
创建数据库
hive (default)> create database mydb; |
切换数据库
hive (default)> use mydb; |
查看数据库
hive (mydb)> show databases; |
删除数据库
hive (default)> drop database mydb; |
3.3 表相关
在hive中表分为两种:
- 托管表:删除表时,数据也删除了。(默认,即将数据也托管给Hive)
- 外部表:删除表时,数据不删除。(只是维护一个目录结构)
查看库中所有表
$hive>show tables in mydb; |
创建表
$hive>CREATE [EXTERNAL] TABLE IF NOT EXISTS t1(id int,name string,age int) [COMMENT 'xx'] ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' lines terminated by '\n' STORED AS TEXTFILE; |
EXTERNAL(可选):外部表
COMMENT:注释
ROW FORMAT DELIMITED FIELDS TERMINATED BY:
lines terminated by:
STORED AS TEXTFILE:文本文件存储
通过hive (mydb)> dfs -lsr /; 即在hive中执行查看HDFS命令,执行速度会大大提高。同时,也可以看到在hive中创建的内容在hdfs上的情况。
删除表
$hive>drop table t; |
添加数据
使用insert(不推荐)
Codehive (mydb)> insert into t1 values(1,'tom',10);
insert操作走MR程序,所以过程非常慢,实际开发中一般不会进行该操作。可能会促发内存不足异常,解决方法在下面。
使用load
查看HDFS文件:
可以看到文件并不是放在一起的,而是没进行一次操作,都会新增一个文件。
查看表结构
hive (mydb)> desc [formatted] t1; |
不带formatted(简略版):
带formatted(详细版):
查看表数据
- select count(*) from t1; (走MR)
- select id,name from t1; (不走MR)
- select * from t1 order by id desc; (走MR)
说明只要有设计到聚合相关的,都会走MR程序。
复制表
携带数据和表结构
Codehive (mydb)> create table t2 as select * from t1;
不带数据,仅表结构
Codehive (mydb)> create table t3 like t1;
分区表
创建分区表
Codehive (mydb)> create table t4(id int,name string,age int) PARTITIONED BY (Year INT,Month INT) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
PARTITIONED BY (Year INT,Month INT):分区字段
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’:分隔符
添加分区,创建目录
Codehive (mydb)> alter table t4 add partition(year=2020,month=12);
可以看到,分区的目录结构。其实就是在HDFS上多了几层条件目录。
显示表的分区信息
Codehive (mydb)> show partitions t4;
加载数据到分区
Codehive (mydb)> load data local inpath '/home/wbw/tmp/data1.txt' into table t4 partition(year=2020,month=11);
这时候查看表内容,发现多了两个字段?其实是目录,没有字段。。。但是可以用where条件分区查看。
删除分区
Codehive (mydb)> ALTER TABLE t4 DROP IF EXISTS PARTITION (year=2014, month=11);
可以看到只剩下一个month=12的分区了
动态分区
动态分区模式:
strict:严格模式,插入时至少指定一个静态分区
nonstrict:非严格模式,可以不指定静态分区。
Code// 1.设置非严格模式
$hive>set hive.exec.dynamic.partition.mode=nonstrict;
// 2.向分区表添加数据(因为Hive中一般不进行insert操作,如果要添加都是Load)
$hive>INSERT [OVERWRITE] TABLE <employees> PARTITION (<country>, <state>) SELECT ..., se.cnty, se.st FROM staged_employees se WHERE se.cnty = 'US';
解析:
前提是有一个分区表,里面有country和state为分区字段。其次,select查询结果里面有该分区字段。
将后面select查询结果,添加到employees表中,以country和state为分区字段。
桶表
即hash算法,可以获得更快的查询速度。
创建桶表
Codehive (mydb)> create table t5(id int,name string,age int) CLUSTERED BY (id) INTO 3 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
CLUSTERED BY (id) INTO 3 BUCKETS:根据id分3个桶
Q:如何确定桶的数量?
A:评估数据量,保证每个桶的数据量block的2倍大小。
添加数据
导出表
hive (mydb)> EXPORT TABLE t5 TO '/user/wbw/export'; |
3.4 查询操作
order全排序
hive (mydb)> select * from t5 order by age; |
运行结果:
OK |
sort排序
map端排序,本地有序。
hive (mydb)> select * from t5 sort by age; |
结果同上order排序
DISTRIBUTE BY分区
类似于mysql的group by,进行分区操作。注意顺序.(先分区再排序)
hive (mydb)> select id,age from t5 distribute by age sort by age desc; |
运行结果:
OK |
3.5 函数
Tab函数列表
$hive>(Tab键) |
concat连接
hive (mydb)> select concat('tom',100); |
数据库、用户信息
hive (mydb)> select current_database(),current_user() ; |
聚合函数
$hive>select cid,count(*) c ,max(price) from orders group by cid having c > 1 ; |
3.6 UDF用户自定义函数
导入pom依赖
xml<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.2</version>
</dependency>创建类,继承UDF
javaimport org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
/**
* 自定义hive函数
*/
"myadd", (name =
value = "myadd(int a , int b) ==> return a + b ",
extended = "Example:\n"
+ " myadd(1,1) ==> 2 \n"
+ " myadd(1,2,3) ==> 6;")
public class AddUDF extends UDF {
public int evaluate(int a ,int b) {
return a + b ;
}
public int evaluate(int a ,int b , int c) {
return a + b + c;
}
}打成jar包
添加jar包到hive的类路径
Code$>cp /xxx/HiveDemo.jar /soft/hive/lib
重进入hive
创建临时函数
CodeCREATE TEMPORARY FUNCTION myadd AS 'XXX.XXX.XXX.XXX.AddUDF';
在查询中使用自定义函数
Code$hive>select myadd(1,2);
四、JDBC访问Hive
4.1 远程jdbc方式连接
启动hiveserver2服务器,监听端口10000
Code$>hive --service hiveserver2 &
通过beeline命令行连接到hiveserver2
Code# 进入beeline命令行(于hive --service beeline)
$>beeline
# 查看帮助
$beeline>!help
# 退出
$beeline>!quit
# 连接到hive数据
$beeline>!connect jdbc:hive2://localhost:10000/mydb2
$beeline>show databases ;
$beeline>use mydb2 ;
# 显式表
$beeline>show tables;
4.2 Hive-jdbc驱动程序
添加依赖
xml<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>3.1.2</version>
</dependency>编写JAVA
java/**
* App class
* Hive-JDBC连接操作
*
* @author BoWenWang
* @date 2020/3/3 15:02
*/
public class App {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("org.apache.hive.jdbc.HiveDriver");
Connection conn = DriverManager.getConnection("jdbc:hive2://192.168.174.201:10000/mydb", "wbw", "Bow1024");
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select id,name,age from t5");
while (rs.next()) {
System.out.println(rs.getInt(1) + "," + rs.getString(2));;
}
rs.close();
statement.close();
conn.close();
}
}打印结果:
Code3,tom
3,tom
4,tom
1,tom
4,tom
1,tom
5,tom
2,tom
5,tom
2,tom
五、事务
使用事务要求:
- 所有事务自动提交。
- 只支持orc格式。
- 使用bucket表。
- 配置hive参数,使其支持事务。
5.1 配置属性
$hive>SET hive.support.concurrency = true; |
5.2 使用事务性操作
$>CREATE TABLE tx(id int,name string,age int) CLUSTERED BY (id) INTO 3 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' stored as orc TBLPROPERTIES ('transactional'='true'); |
六、视图
和MySQL一样,视图只是表的关系映射,实际上是不存在的表。
6.1 创建视图
$hive>create view v1 as select a.id aid,a.name ,b.id bid , b.order from customers a left outer join default.tt b on a.id = b.cid ; |
6.2 查看视图
$hive>select * from v1 ; |
七、调优
7.1 explain
使用explain查看查询计划
hive>explain [extended] select count(*) from customers ; |
extended:更详细
7.2 limit
设置limit优化测,避免全部查询
hive>set hive.limit.optimize.enable=true |
7.3 严格模式
$hive>set hive.mapred.mode=strict |
开启后的限制:
- 分区表必须指定分区进行查询
- order by时必须使用limit子句。
- 不允许笛卡尔积.
7.4 设置MR的数量
// 设置reducetask的字节数。 |
7.5 JVM重用
$hive>set mapreduce.job.jvm.numtasks=1 //-1没有限制,使用大量小文件。 |
7.6 数据倾斜
$hive>SET hive.optimize.skewjoin=true; |
八、问题汇总
8.1 虚拟内存不足
https://blog.csdn.net/weixin_33725722/article/details/92442061
当进行计算的操作时候,可能发生内存不足的情况,如上面的表插入insert时候。
8.2 JDBC-Hive连接不上
Error: Could not open client transport with JDBC Uri: jdbc:hive2://localhost:10000/mydb;: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: wbw is not allowed to impersonate root (state=08S01,code=0)
解决方法:
https://blog.csdn.net/finejade1027/article/details/91637283
User: wbw is not allowed to impersonate root .
hadoop.proxyuser.root.hosts配置项名称中root部分为报错User:* 中的用户名部分,根据需要修改。如这里的wbw,那就要修改成wbw。所有节点都要改!然后重新连接后,用户名输入wbw
<!--在core-site.xml添加如下内容后,重启Hadoop --> |
九、注意事项
如果配置hadoop HA之前,搭建了Hive的话,再HA之后,需要调整路径信息。
主要是修改mysql中的dbs,tbls等相关表。