Hive表的相关操作
Hive是一个数据仓库,它可以把结构化的数据文件映射为一张数据库表,并且有SQL语言的查询功能。
注意:一般来说数据仓库存放的是一些历史数据,它的作用是用来做查询分析,往往不会用来做单条记录的增加、删除、修改
Hive表的创建语法与传统的关系型数据库类似,它是它的类型会更加复杂一些,如:它的类型可以是数组、Map……
一、创建Hive表
如下我们创建一张Hive表。
表名:person
字段包含:id,name,age,fav,addr
数据类型分别为:int,String,int,String数组,Map<String,String>
建表语句:
CREATE TABLE person(
id INT,
name STRING,
age
INT,
fav
ARRAY<STRING>,
addr
MAP<STRING,STRING>
)
COMMENT 'This is the person table'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':'
STORED AS TEXTFILE;
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' 这个用来设定每一个字段的分隔符,这里的'\t'表示使用Tab键来进行分隔每行字段
COLLECTION ITEMS TERMINATED BY '-' 这个用来表示集合类型中每个对象的分隔符
fav ARRAY<STRING> 这个表示fav为字符串的数组类型
MAP KEYS TERMINATED BY ':' 这个用来定义MAP类型的键值对的分隔符
STORED AS TEXTFILE 这个表示使用数据文件格式,这里指的是txt类型
二、数据导入
在Hive中会把结构化的数据映射为一张表,上述建立的有是一个txt格式的文件,注意这个txt文件中的内容必须要按照表定义的分隔符进行分隔。
导入文件数据:
新建一个txt文件 data.txt
1 rod 18 study-game-driver std_addr:beijing-work_addr:shanghai
2 tom 21 study-game-driver std_addr:beijing-work_addr:beijing
3 jerry 33 study-game-driver std_addr:beijing-work_addr:shenzhen
导入文件命令如下:
load data local inpath '/root/data.txt' overwrite into table person;
导入成功后,查询表数据:
select * from person;
三、表的分区与分桶
表进行分区 与分桶的目的是防止对表中数据的全量扫描,从而提升查询的性能。
删除表操作:drop table person;
-
表的分区(在建立表时指定分区)
CREATE TABLE person(
id INT,
name STRING,
age
INT,
fav
ARRAY<STRING>,
addr
MAP<STRING,STRING>
)
COMMENT 'This is the person table'
PARTITIONED BY(
dt
STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':'
STORED AS TEXTFILE;
在上面的建表语句中,指定了以String类型的字段dt为依据进行分区,对于导入数据也存在一定的区别,在导入数据时也要指定导入哪一个分区中
load data local inpath '/root/data.txt' overwrite into table person partition(dt='20200512');
查询数据
select * from person where dt='20200512';
select addr['work_addr'] from person where dt=20200512;
四、表的分桶
分桶是相对于分区进行更加细粒度的划分,一旦当分区数量过于庞大时,我们就需要采用分桶来解决了。
分桶是把整个数据内容按某列属性值的Hash值进行区分
分桶应该在建立表时进行建立
CREATE TABLE person(
id INT,
name STRING,
age INT,
fav ARRAY<STRING>,
addr MAP<STRING,STRING>
)
COMMENT 'This is the person table'
PARTITIONED BY(dt STRING)
clustered by (id) into 3 buckets
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY '-'
MAP KEYS TERMINATED BY ':'
STORED AS TEXTFILE;
上面的建表语句是分为三个桶,那如果要查找第一个桶中的所有数据查询语句如下:
select * from person tablesample(bucket 1 out of 3 on id);
如果运行过程中报错:is running 460233216B beyond the 'VIRTUAL' memory limit.
一般是虚拟内存设置的不对的原因
解决方案:
在hadoop的配置文件目录中,对mapred-site.xml中添加如下配置
<property>
<name>mapreduce.map.memory.mb</name>
<value>2048</value>
</property>
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>2048</value>
</property>
HA集群发现其中一个备NN无法启动
解决方案:
将能够启动的namenode节点的tmp/dfs/name目录下面的文件拷贝到不能启动的namenode节点上
然后重启hdfs
五、内部表与外部表
Hive创建的表分为内部表和外部表,对于内部表来说,在创建的时候会把数据移动到数据仓库指向的位置,如果是外部表,则仅仅记录数据所在的位置。
对于内部表,在删除的时候会把元数据和数据一起删除,外部表则仅仅只删除元数据,真正的数据不会删除。因而在共享源数据的情况下,可以选择使用外部表。
-
内部表
数据文件的全部操作都是由Hive来完成的,除此外不会有其它的应用使用这个数据文件
-
外部表
在实际的应用中数据文件可能不仅仅是由Hive来操作,这时一般是不可以改变数据文件的格式及位置的,这时一般是用外部表来实现Hive操作
外部表的创建方式
-
创建一张空表,然后导入数据
create
external table person(
id int,
name string,
age int,
fav array<string>,
addr map<string,string>
)
comment 'this is a person table'
row format delimited fields terminated by '\t'
collection items terminated by '-'
map keys terminated by ':'
stored as textfile;
注意:上面的建表语句使用了external关键字
-
导入数据:load data local inpath '/root/data.txt' overwrite into table person;
-
查看数据:dfs -ls /usr/hive/warehouse/person;
查看数据是可以看到:/usr/hive/warehouse/person/
data.txt
六、内置函数与自定义函数
Hive中包含了一些自定义的函数,如果内置函数不满足需求,我们也可以编写自定义函数(UDF:User Defined Function)
UDF函数有如下三种类型:
-
UDF:用于单条数据,并且输出一个数据行,大多数函数属于这一类
-
UDAF:可以接受多个输入,同时输出一个数据行
-
UDTF:用于单个数据行同时产生多个输出数据行
创建一个虚拟txt文件
echo 'X' > dual.txt
创建一个虚拟表dual
create table dual (dummy string);
导入数据
load data local inpath '/root/dual.txt' overwrite into table dual;
拼接函数concat
select concat('a','b','c','d') from dual;
输出结果:abcd
统计记录行count
select count(1) from dual;
输出结果:1
拆分字符串并逐行输出explode、split
select explode(split('a,b,c,d,e',',')) from dual;
输出结果:
a
b
c
d
e
自定义函数
java代码:
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.IntWritable;
public class Maximum extends UDAF {
public static class MaximumIntUDAFEvaluator implements UDAFEvaluator{
private IntWritable result;
@Override
public void init() {
result = null;
}
public boolean iterate(IntWritable value){
if(value == null){
return true;
}
if(result == null){
result = new IntWritable(value.get());
} else {
result.set(Math.max(result.get(),value.get()));
}
return true;
}
public IntWritable terminatePartial(){
return result;
}
public boolean merge(IntWritable other){
return iterate(other);
}
public IntWritable terminate(){
return result;
}
}
}
将代码打包为jar包
1.file-->Project Structure-->Artifacts

2.输入jar包的名称,Output directory的路径
3.添加好对应的包路径

4.添加对应的class文件

5.打包为jar包

上传jar包到服务器
向Hive中添加jar包
add jar /root/Maximum.jar;
使用jar包来生成一个自定义函数
create function maximumtext as 'com.xiaoxie.hive.Maximum';
测试自定义函数
select maximumtest(id) from person;
返回结果:3
七、通过JAVA访问Hive
JAVA代码与访问JDBC操作一致
import java.sql.*;
public class HiveTest {
private static final String DRIVER = "org.apache.hive.jdbc.HiveDriver";
private static final String DATABASE_PATH="jdbc:hive2://192.168.2.2:10000/default";
private static final String USER_NAME="root";
private static final String PASSWORD="123456";
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String hql = "select count(1) from person";
int count = 0;
try {
//注册驱动
Class.forName(DRIVER);
//创建连接
conn = DriverManager.getConnection(DATABASE_PATH,USER_NAME,PASSWORD);
//创建statement
stmt = conn.createStatement();
//执行hql语句
rs = stmt.executeQuery(hql);
//处理结果集
if(rs.next()){
count = rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
if(rs != null)
rs.close();
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
}
System.out.println(count);
}
}
注意:这里需要导的包是:hive-jdbc-3.1.2.jar
执行时报错:
Error: Could not open connection to jdbc:hive2://192.168.2.2:10000/default: java.net.ConnectException: Connection refused (Connection refused) (state=08S01,code=0)
解决方案:
1.进入到hive的配置目录conf,修改配置文件hive-site.xml
添加如下如下配置
<!--hive server2的超时时间,默认是5000-->
<property>
<name>hive.server2.long.polling.timeout</name>
<value>5000</value>
<!--尤其注意时间是5000,原配置文件中会多个L,需要去掉-->
</property>
<!-- hive server2的使用端口,默认就是10000-->
<property>
<name>hive.server2.thrift.port</name>
<value>10000</value>
</property>
<!-- hive server2绑定的主机名-->
<property>
<name>hive.server2.thrift.bind.host</name>
<value>hadoop21</value>
</property>
2.启动hive的后台服务
hive --service hiveserver2 &
beeline
!connect jdbc:hive2://192.168.2.2:10000 root
输入上面命令后输入对应的密码
如果报错如下: root is not allowed to impersonate root
解决方案:
1.在hadoop的配置文件core-site.xml中添加如下属性:
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
2.重启hdfs
3.如果还报错,则表示hive所在的节点并不是active的节点(可以访问
http://192.168.2.2:9870/dfshealth.html),可以看到当前节点如果是
standy。需要把它所在的节点切换为active
运行java程序在linux后台可以看到执行的过程,最后执行完成后会在控制台打印出执行的结果。(注意在运行前一定要启动hive)