Hive学习

Hive

Hive引言

hive是faceBook开源,并捐献给了apache组织,作为apache的顶级项目项目。 地址:hive.apache.org。hive是一个基于大数据的数据仓库技术(DataWareHouse,简称数仓),底层依附HDFS、MapReduce

hive的优点:书写sql语句,由hive把sql转换为MapReduce,简化开发
hive的缺点:无法作为实时查询,不适合小数据处理,不适合数据挖掘
hive的运行原理:

hive通过sql操作HDFS上的文件,那就需要将HDFS上的文件作为一张表处理,那就需要有对应关系,
hive表-->HDFS上的文件,sql操作的列-->HDFS上文件中的数据
使用HDFS进行存储,使用MapReduce进行计算。

在这里插入图片描述

Hive环境的搭建

  1. linux服务器 ip 映射 主机名 关闭防火墙 关闭selinux ssh免密登陆 jdk
  2. 搭建hadoop环境
  3. 安装Hive
    3.1 解压缩hive 
    3.2 hive_home/conf/hive-env.sh [改名,原名后面还有个template]  #hive_home是指自己安装hive的位置
      	#hadoop的安装路径
        HADOOP_HOME=/opt/install/hadoop-2.5.2   
        #hive的安装路径下的配置文件夹
        export HIVE_CONF_DIR=/opt/install/apache-hive-0.13.1-bin/conf
    	#下面替换MetaStore时,会修改另一个配置文件,下面单独说
    3.2 hdfs创建2个目录
        /tmp
        /user/hive/warehouse
        bin/hdfs dfs -mkdir /tmp
        bin/hdfs dfs -mkdir -p /user/hive/warehouse
    3.2.5 修改hive的日志地址(可以没有这步,那hive日志会生成在系统默认位置)
    	hive_home/conf/hive-log4j.properties配置文件	#hive_home是指自己安装hive的位置
    	hive.log.dir=hive_home/logs
    3.3 启动hive
        bin/hive 
    3.4 jps
        runjar
    

Hive 常用交互命令

在这里插入图片描述

1. “-e”不进入 hive 的交互窗口执行 sql 语句
例如: bin/hive -e "select id from student;"
可以跟多条sql,用;隔开就行  bin/hive -e "sql1;sql2;sql3"
2. “-f”执行脚本中 sql 语句
例如:在hive安装目录/下创建 datas 目录并在 datas 目录下创建 hivef.sql 文件
	touch hivef.sql
	select *from student;  #hivef.sql中写入的sql
	bin/hive -f hive_home/datas/hivef.sql    #执行sql文件
	#执行sql文件并将结果写入某个文件汇总
	bin/hive -f hive_home/datas/hivef.sql > root/hive_result.txt

Hive基本操作

# 创建数据库
create database [if not exists] 数据库名;
# 查看所有数据库
 show databases;
# 使用数据库
 use 数据库名;
# 删除空数据库 
 drop database 数据库名;
#删除非空数据库,也可删空数据库
 drop database 数据库名 cascade;
 
hive中的数据库 本质是 hdfs的目录
数据库会建在 /user/hive/warehouse下,所以搭建hive环境时一定要创建此文件夹
/user/hive/warehouse/数据库名

# 查看当前数据库下的所有表
  show tables;
# 建表语句
  create table t_user(
    id int ,
    name string
   )row format delimited fields terminated by '\t';
此句话的意思,row的格式:列是根据“\t”分割开的,因此“\t”是根据HDFS上的数据来动态修改的,如果HDFS上的数据分割是根据“,”分割的,这里要改为 by“,”

hive中的表  本质是 hdfs的目录 /user/hive/warehouse/数据库名/表名

# 删除表
  drop table 表名;
# 删除表中数据,不删除表
  truncate table 表名;
# hive中向表导入数据
  load data local inpath 'linux数据所在位置' into table 表名;  #导入linux的数据
  例如:load data local inpath '/root/hive/data' into table t_user;
  load data inpath 'hdfs数据所在位置' into table 表名;		#导入hdfs上的数据
  
# hive导入数据的本质
1. 导入数据 本质本质上就是 hdfs 上传文件
  bin/hdfs dfs -put /root/hive/data /user/hive/warehouse/数据库名/表名;
  例如:bin/hdfs dfs -put /root/hive/data /user/hive/warehouse/databases.db/t_user;

2. 上传了重复数据,hive导数据时,会自动修改文件名
3. 查询某一个张表时,Hive会把表中这个目录下所有文件的内容,整合查询出来

# Hive的SQL(类SQL 类似于SQL 称为HQL Hive Query Language)
select * from t_user;
select id from t_user;
1. Hive把SQL转换成MapReduce (如果只是清洗数据 没有Reduce)
2. Hive在绝大多数情况下运行MR,但是在*、 limit(分页)操作时不运行MR

MetaStore的替换问题

Hive中的MetaStore把HDFS对应结构,与表对应结果做了映射(对应)。但是默认情况下hive的metaStore应用的是derby数据库,只支持一个client访问。
derby数据库:下载安装的jdk就有一个默认的derby数据库,此数据库很小,几乎没人使用

Hive中元数据库Derby替换成MySQL(Oracle)
0. 删除hdfs /user/hive/warehouse目录,并重新建立   #若没有存过数据,此项可以跳过
1. 在linux上安装mysql,此次替换为mysql
   yum -y install mysql-server
2. 启动mysql服务并设置管理员密码
   service mysqld start
   /usr/bin/mysqladmin -u root password '123456'
   mysql -u root -p		#登录mysql,然后输入密码
3.打开mysql远程访问权限
#这里的123456为你给新增用户设置的密码,%代表所有主机,也可以具体到主机的ip地址
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
#从mysql数据库的grant表中重新加载权限数据,这步必须得执行
flush privileges;   
use mysql  
select user,host from user;		#将此表中除了 user = root,host = %的数据都删掉
service mysqld restart		#重启mysql服务
4. 创建conf/hive-site.xml
#将hive下配置文件夹下的hive-default.xml.template改名为hive-site.xml
mv hive-default.xml.template hive-site.xml
#hive运行时,不知道操作的表所在的数据库,这里设置显示数据库名,只是为了方便,可以不设置
<property>
  <name>hive.cli.print.current.db</name>
  <value>true</value>
</property>
# 查询表的行头信息,作用同上
<property>
  <name>hive.cli.print.header</name>
  <value>true</value>
</property>

#mysql所在的主机及端口号,metastore数据库,若不存在则创建
<property>
  <name>javax.jdo.option.ConnectionURL</name>
  <value>jdbc:mysql://hadoop21:3306/metastore?createDatabaseIfNotExist=true</value>
  <description>the URL of the MySQL database</description>
</property>

#DriverName
<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>javax.jdo.option.ConnectionUserName</name>
  <value>root</value>
</property>

#密码
<property>
  <name>javax.jdo.option.ConnectionPassword</name>
  <value>123456</value>
</property>

5. hive_home/lib 上传mysql driver jar包,jar包可以去maven仓库上下载
6. 重启hive

Hive的语法细节

1. HQL (SQL)
 1. 基本查询
   select * from table_name # 不启动mr
   select id from table_name # 启动mr
 2. 条件查询 where
   select id,name from t_users where name = '查询条件';
   2.1 比较查询  =  !=  >=  <=
       select id,name from t_users where age > 20;
   2.2 逻辑查询  and or  not
       select id,name,age from t_users where name = '查询条件' or age>查询条件;
   2.3 谓词运算
       between and
       select name,salary from t_users where salary between 100 and 300;
       in
       select name,salary from t_users where salary in (100,300);
       is null
       select name,salary from t_users where salary is null;
       like
       select name,salary from t_users where name like '查询条件';
 3. 排序(order by、Sort By、Distribute By、Cluster By)
	order by [底层使用的是 map sort  group sort  compareto],全局排序,只有一个 Reducer
	select name,salary from t_users order by salary desc;
	
	Sort By:对于大规模的数据集 order by 的效率非常低。在很多情况下,并不需要全局排序,此时可以使用 sort by。
	Sort by 为每个 reducer 产生一个排序文件。每个 Reducer 内部进行排序,对全局结果集来说不是排序。
	Sort by使用:1.设置reduce个数   set mapreduce.job.reduces=3
				 2. 查看设置reduce个数  set mapreduce.job.reduces;
				 3. sql使用sort by    select * from emp sort by deptno desc;
				 4. 将查询结果导入到文件中(3个文件,文件内有序)
				insert overwrite local directory '/opt/module/data/sortby-result' select * from emp sort by deptno desc;
	
	Distribute By:有些情况下,需要控制某个特定行应该到哪个 reducer,通常是为了进行后续的聚集操作。
	distribute by 类似 MR 中 partition(自定义分区),根据某个字段进行分区,结合 sort by 使用。
	# 先按照部门编号分区,再按照员工编号降序排序(写到文件中,看到更直观)
	insert overwrite local directory '/opt/module/data/distribute-result'
	select * from emp distribute by deptno sort by empno desc;
注意:
	1.distribute by 的分区规则是根据分区字段的 hash 码与 reduce 的个数进行模除后,余数相同的分到一个区。
	2.Hive 要求 DISTRIBUTE BY 语句要写在 SORT BY 语句之前。

	Cluster By:当 distribute by 和 sorts by 字段相同时,可以使用 cluster by 方式。排序只能是升序排序,不能指定排序规则为ASC或者DESC。

 4. 去重 distinct
   select distinct(age) from t_users;
 5. 分页 [Mysql可以定义起始的分页条目,但是Hive不可以
   select * from t_users limit 3;     
 6. 聚合函数(分组函数) count() avg() max() min() sum() 
   count(*)  count(id) 区别
 7. 分组 group by
   select max(salary) from t_users group by age;
 8. having   分组后,聚合函数的条件判断用having
   select max(salary) from t_users group by age having max(salary) > 800;
 9. hive不支持子查询
 10. hive内置函数
	show functions  #查看内置函数
	#以下列举几个可能常用的内置函数
    length(column_name)  获得列中字符串数据长度
    substring(column_name,start_pos,total_count)  字符串截取
    concat(col1,col2)  连接两个字段
    to_data('yyyy-mm-dd')  转为日期
    year(data) 获得年份
    month(data)  获得月份
    date_add 日期相加
    date_sub  日期相减
    ....
    select year(to_date('1999-10-11')) ;    #hive中没有dual表
	#查询某个函数怎么使用,例如查看upper怎么使用
	desc function upper;
	
 11. 多表操作
	inner join
	left join
	right join
	full join 

hive无update delete操作,有ALTER TABLE DROD和INSERT OVERWRITE TABLE操作

hive的UDF、UDAF、UDTF函数区别
UDF:一进一出
UDAF:多进一出
UDTF:一进多出
1.1 行转列
CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串;
例如:CONCAT(A列,B列):将A列和B列连接起来;结果A列B列
	CONCAT(a,b):将a字符串和b字符串连接起来;结果ab
CONCAT(string A/col, '--',string B/col,'**',string C/col…):按指定字符连接
例如:CONCAT(A列,'--',B列,'++',C列)			结果:A列--B列--C列
	CONCAT(aa,'**',bb,'//',cc)				结果:aa**bb//cc
	
CONCAT_WS(separator, str1, str2,...):它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。
分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。
select concat_ws('--',name,'333','444')from class_test; 	结果:name列--333-444
select concat_ws('null',name,'333','444')from class_test;	结果:name列null333null444
select concat_ws(NULL,name,'333','444')from class_test;		结果:NULL(分隔符是NULL,返回值都是NULL)
注意: CONCAT_WS must be "string or array<string>:连接的数据只能是string或者string集合

collect_list和collect_set:都是将分组中的某列转为一个数组返回,不同的是collect_list不去重而collect_set去重。
数据如下:t_visit_video 
username	video_name
张三			大唐双龙传
李四			天下无贼
张三			神探狄仁杰
李四			霸王别姬
李四			霸王别姬
王五			机器人总动员
王五			放牛班的春天
王五			盗梦空间
1.按用户分组,取出每个用户每天看过的所有视频的名字:(电影名字不去重)
select username, collect_list(video_name) from t_visit_video group by username ;
结果:
张三		["大唐双龙传","神探狄仁杰"]
李四		["天下无贼","霸王别姬","霸王别姬"]
王五		["机器人总动员","放牛班的春天","盗梦空间"]
2.按用户分组,取出每个用户每天看过的所有视频的名字:(电影名字去重)
select username, collect_set(video_name) from t_visit_video group by username;
结果:
张三		["大唐双龙传","神探狄仁杰"]
李四		["天下无贼","霸王别姬"]
王五		["机器人总动员","放牛班的春天","盗梦空间"]
1.2 列转行
EXPLODE(col):将 hive一列中复杂的Array或者Map结构拆分成多行。
LATERAL VIEW:用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
lateral view 首先将utdf函数应用到每一行上,这时每一行经utdf处理后得到多行输出,这些输出将会组建成一张虚拟表,然后这张虚拟表会跟当前表进行join操作
数据如下: movie_info
movie			category
《疑犯追踪》 	悬疑,动作,科幻,剧情
《Lie to me》	悬疑,警匪,动作,心理,剧情
《战狼 2》		战争,动作,灾难

将电影分类中的数组数据展开
SELECT movie,category_name FROM movie_info 
lateral VIEW explode(split(category,",")) movie_info_tmp AS category_name;
结果:
《疑犯追踪》		悬疑
《疑犯追踪》		动作
《疑犯追踪》		科幻
《疑犯追踪》		剧情
《Lie to me》		悬疑
《Lie to me》		警匪
《Lie to me》		动作
《Lie to me》		心理
《Lie to me》		剧情
《战狼 2》		战争
《战狼 2》		动作
《战狼 2》		灾难

1.3 开窗函数
over():窗口函数,在括号中指定开窗条件,通常和聚合函数、排名函数一起使用。如果开窗条件为空,
		那么聚合的是过滤后的整张表。在SQL处理中,窗口函数都是最后一步执行,而且仅位于Order by字句之前。
使用条件:数据既需要原始数据,又需要聚合数据
over和聚合函数一起使用时,给结果起别名,在over后,例如:count(*) over() cnt;  cnt就是count起的别名

开窗条件
PARTITION BY:指定分组条件。
ORDER BY:指定组内排序条件。
CURRENT ROW:当前行。
n PRECEDING:前n行。
n FOLLOWING:后n行。
UNBOUNDED:无限的。UNBOUNDED PRECEDING 第一行,UNBOUNDED FOLLOWING最后一行。
LAG(字段名,n):某一列当前行的前n行。
LEAD(字段名,n):某一列当前行的后n行。
NTILE(n):将数据分组并发送到不同窗口,返回组号。

排名函数
RANK():排名有重复,总数不会变。  			1,1,3			3条数据,有并列第一,但排名还是到3
DENSE_RANK():排名有重复,总数会减少。		1,1,2			3条数据,有并列第一,排名减少
ROW_NUMBER():按顺序排名,无重复。			1,2,3			3条数据,有并列第一(1,2一样),排名不重复且不减少

--创建表如下
create table business(
name string, 
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

-- 数据如下
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94


//1.查询在2017年4月份购买过的顾客及总人数
-- over()不写开窗条件,聚合的是过滤后的整张表
SELECT name,count(*) over() cnt
FROM business WHERE substring(orderdate,1,7)='2017-04' GROUP BY name;
--结果
name    cnt
mart    2
jack    2


//2.查询顾客的购买明细及月销售总额
-- 按照月份分组,组内相加
SELECT name,orderdate,cost,SUM(cost) OVER(PARTITION BY substring(orderdate,1,7)) mtotal FROM business;
select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) from business;
--结果
name    orderdate       cost    mtotal
jack    2017-01-01      10      205
jack    2017-01-08      55      205
tony    2017-01-07      50      205
jack    2017-01-05      46      205
tony    2017-01-04      29      205
tony    2017-01-02      15      205
jack    2017-02-03      23      23
mart    2017-04-13      94      341
jack    2017-04-06      42      341
mart    2017-04-11      75      341
mart    2017-04-09      68      341
mart    2017-04-08      62      341
neil    2017-05-10      12      12
neil    2017-06-12      80      80


//3.总销售额
-- over()中不写开窗条件就是统计整张表
SELECT name,orderdate,cost,SUM(cost) OVER() total FROM business;
--结果
name    orderdate       cost    total
mart    2017-04-13      94      661
neil    2017-06-12      80      661
mart    2017-04-11      75      661
neil    2017-05-10      12      661
mart    2017-04-09      68      661
mart    2017-04-08      62      661
jack    2017-01-08      55      661
tony    2017-01-07      50      661
jack    2017-04-06      42      661
jack    2017-01-05      46      661
tony    2017-01-04      29      661
jack    2017-02-03      23      661
tony    2017-01-02      15      661
jack    2017-01-01      10      661


//4.每个人的消费总额
-- 根据姓名分区,组内相加
SELECT name,orderdate,cost,SUM(cost) OVER(PARTITION BY name) ev_cost FROM business;
--结果
name    orderdate       cost    ev_cost
jack    2017-01-05      46      176
jack    2017-01-08      55      176
jack    2017-01-01      10      176
jack    2017-04-06      42      176
jack    2017-02-03      23      176
mart    2017-04-13      94      299
mart    2017-04-11      75      299
mart    2017-04-09      68      299
mart    2017-04-08      62      299
neil    2017-05-10      12      92
neil    2017-06-12      80      92
tony    2017-01-04      29      94
tony    2017-01-02      15      94
tony    2017-01-07      50      94


//5.每个人截至到当前行的消费额累加
-- 按照姓名分组,从第一行到当前行累加
SELECT name,orderdate,cost,
SUM(cost) OVER(PARTITION BY name ORDER BY orderdate) ev_cur_cost FROM business;

SELECT name,orderdate,cost,
SUM(cost) OVER(PARTITION BY name ORDER BY orderdate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ev_cur_cost2
FROM business;
--结果
name    orderdate       cost    ev_cur_cost
jack    2017-01-01      10      10
jack    2017-01-05      46      56
jack    2017-01-08      55      111
jack    2017-02-03      23      134
jack    2017-04-06      42      176
mart    2017-04-08      62      62
mart    2017-04-09      68      130
mart    2017-04-11      75      205
mart    2017-04-13      94      299
neil    2017-05-10      12      12
neil    2017-06-12      80      92
tony    2017-01-02      15      15
tony    2017-01-04      29      44
tony    2017-01-07      50      94


//6.每个人上一次购物与此次购物的总额
-- 按姓名分组,组内前一行和当前行相加
SELECT name,orderdate,cost,
SUM(cost) OVER(PARTITION BY name ORDER BY orderdate ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) ev_pre_cost FROM business;


//7.每个人连续三次购物的总额
-- 按姓名分组,组内连续三次相加
SELECT name,orderdate,cost,
SUM(cost) OVER(PARTITION BY name ORDER BY orderdate ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) ev_con_cost FROM business;


//8.每个人当前行与后面所有行的累计额
-- 按照姓名分组,当前行与后面所有行的累加
SELECT name,orderdate,cost,
SUM(cost) OVER(PARTITION BY name ORDER BY orderdate ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) ev_foll_cost FROM business;

//9.查看顾客上次的购买时间
-- 购买日期列当前行的前1行,只查看上次购买时间,不用分组
SELECT name,orderdate,cost,
LAG(orderdate,1) OVER(ORDER BY orderdate) lag_cost_time FROM business;

//10.查询前20%时间的订单信息
-- 数据按照时间分为5组,取第一组的数据
SELECT * FROM(SELECT name,orderdate,cost,
NTILE(5) OVER(ORDER BY orderdate) n FROM business) tbl WHERE n=1;

//11.有哪些顾客连续两(或n)天来过我的店
-- 1.先给数据按姓名分组,按日期排序并加行号
SELECT name,orderdate,
ROW_NUMBER() OVER(PARTITION BY name ORDER BY orderdate) n
FROM business;
-- 2.日期与行号相减,如果连续两(或n)行结果一致,那么就是连续两(或n)天都来过
SELECT *,DATE_SUB(orderdate,n) ds
FROM (SELECT name,orderdate,
ROW_NUMBER() OVER(PARTITION BY name ORDER BY orderdate) n
FROM business) t1;
-- 3.count聚合,大于等于2(或n)就是连续两(或n)天都来过
SELECT name,count(*) c
FROM (
    SELECT *,DATE_SUB(orderdate,n) ds
    FROM (
        SELECT name,orderdate,
        ROW_NUMBER() OVER(PARTITION BY name ORDER BY orderdate) n
        FROM business) t1
    )t2
GROUP BY name,ds HAVING c>=2;



name	subject	score
孙悟空  语文    87
孙悟空  数学    95
孙悟空  英语    68
大海    语文    94
大海    数学    56
大海    英语    84
宋宋    语文    64
宋宋    数学    86
宋宋    英语    84
婷婷    语文    65
婷婷    数学    85
婷婷    英语    78

//计算每门学科成绩排名
SELECT subject,name,score,
RANK() OVER(PARTITION BY subject ORDER BY score DESC) rk,
DENSE_RANK() OVER(PARTITION BY subject ORDER BY score DESC) drk,
ROW_NUMBER() OVER(PARTITION BY subject ORDER BY score DESC) rnm FROM score;

在这里插入图片描述
hive开窗函数TopN

//获取Top3
select t2.* from(
   select pid,uid,cnt,row_number() over (partition by pid order by cnt desc ) as rank from 
      (
         select pid,uid,count(uid) as cnt from visit2 group by pid,uid order by pid,cnt desc
      ) as t1
   ) as t2
where t2.rank <= 3;

1.先根据pid,uid分组并统计uid的个数
select pid,uid,count(uid) as cnt from visit2 group by pid,uid order by pid,cnt desc
2.开窗函数和row_number()一起使用,对数据进行排名和降序排序
select pid,uid,cnt,row_number() over (partition by pid order by cnt desc ) as rank from t1
3.获取前N条数据即是TopN
select t2.* from t2 where t2.rank <= 3;
1.4 自定义 UDF 函数

需求:自定义一个 UDF 实现计算给定字符串的长度

1.创建一个Maven工程Hive
2.导入依赖
<dependency>
	<groupId>org.apache.hive</groupId>
	<artifactId>hive-exec</artifactId>
	<version>3.1.2</version>
</dependency>
3.创建一个类继承GenericUDF类

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

/**
 * 自定义 UDF 函数,需要继承 GenericUDF 类
 * 需求: 计算指定字符串的长度
 */
public class MyStringLength extends GenericUDF {
    /**
     * @param arguments 输入参数类型的鉴别器对象
     * @return 返回值类型的鉴别器对象
     * @throws UDFArgumentException
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws
            UDFArgumentException {

        // 判断输入参数的个数
        if (arguments.length != 1) {
            throw new UDFArgumentLengthException("Input Args Length Error !!!");
        }
        // 判断输入参数的类型
        if (!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)) {
            throw new UDFArgumentTypeException(0, "Input Args Type Error !!!");
        }
        //函数本身返回值为 int,需要返回 int 类型的鉴别器对象
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    /**
     * 函数的逻辑处理
     *
     * @param arguments 输入的参数
     * @return 返回值
     * @throws HiveException
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws
            HiveException {
        if (arguments[0].get() == null) {
            return 0;
        }
        return arguments[0].get().toString().length();
    }

    @Override
    public String getDisplayString(String[] children) {
        return "";
    }
}
4.打成 jar 包上传到服务器/opt/module/data/myudf.jar
5.将 jar 包添加到hive的classpath 或者将jar包直接上传到hive的lib包,然后重新进入hive
hive (default)> add jar /opt/module/data/myudf.jar;
6.创建临时函数与开发好的 java class 关联
hive (default)> create temporary function my_len as "com.hive.MyStringLength";
7.在sql中使用自定义的函数
select ename,my_len(ename) ename_len from emp;
2. 表相关的操作
细节
  1. 数据类型

int、string、varchar、char、double、float、boolean、STRUCT、MAP、ARRAY… 更多的看文档,文档地址

  1. location hdfs_path

定制创建表的位置,默认是 /user/hive/warehouse/db_name.db/table_name
create table table_name(
id,int
name,string
)row format delimited fields terminated by ‘\t’ location ‘/dir’;
会将表创建在hdfs的dir目录下
作用:之前的逻辑是:先创建表,然后将数据上传到表的目录中,形成对应关系;但当指定表的位置后,如果hdfs上已经有数据了,此时可以直接在此目录下创建表,直接形成对应关系,没必要再将数据复制一份到hive的目录下,这种才是生产环境比较常见的情况

  1. 查看hive表结构的命令

desc/describe table_name 查看表结构 只是描述了表的列和列的类型
desc extended table_name 表的详细信息,但这种看着比较麻烦
desc formatted table_name 表的详细信息,和extended 一样,但可读性比较好

创表语法字段说明
#创表语句
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]

#字段说明:
CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径(LOCATION),在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
COMMENT:为表和列添加注释
PARTITIONED BY 创建分区表
CLUSTERED BY 创建分桶表
SORTED BY 不常用,对桶中的一个或多个列另外排序
ROW FORMAT DELIMITED FIELDS TERMINATED BY:指定字段分隔符
					 MAP KEYS TERMINATED BY:map 分隔符(hive是可以存map数据的)
					 LINES TERMINATED BY:行分隔符
STORED AS: 指定存储文件类型;常用的存储文件类型:SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)
		如果文件数据是纯文本,可以使用STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
LOCATION :指定表在 HDFS 上的存储位置。
AS:后跟查询语句,根据查询结果创建表。
LIKE 允许用户复制现有的表结构,但是不复制数据。
创建表
2.1 管理表 (MANAGED_TABLE)
1. 基本管理表的创建
create table if not exists table_name(
column_name data_type,
column_name data_type
)row format delimited fields terminated by '\t'    [location 'hdfs_path']

2. as 关键字创建管理表
create table if not exists table_name as select id,name from t_users [location ''];
表结构由查询的列决定,同时会把查询结果的数据插入新表中

3. like 关键字创建管理表
create table if not exists table_name like t_users [location 'hdfs_path'];
表结构和like关键字后面的表一致,但是表没有数据,是空表
2.2 外部表(建表时多个external关键字)
4. 基本外部表创建
create external table if not exists table_name(
id int,
name string
) row delimited fields terminated by '\t' [location 'hdfs_path'];
5. as 
create external table if not exists table_name as select id,name from t_users [location ''];
6. like
create external table if not exists table_name like t_users [location 'hdfs_path'];

管理表和外部表的区别:除了创建表的sql、表的类型之外的区别

1:管理表和外部表的区别
drop table t_users_as; 删除管理表时,既删除metastore,同时删除hdfs的目录和数据文件
drop table t_user_ex; 删除外部表时,只删除metastore的数据,不会删原始数据

2:外部表与管理表使用方式的区别
当有多个人要操作此表时,肯定需要不同的数据权限,那么就可以创建个管理表给管理员使用;创建外部表给普通用户使用; 只要location hdfs_path 相同即可

管理表与外部表的互相转换
desc formatted table_name; //查询表类型
alter table table_name set tblproperties(‘EXTERNAL’=‘TRUE’); //将表设为外部表 true:外部表;false:非外部表

2.3 分区表【查询优化,避免全表扫描】(关键字:partitioned by)

作用:用于提高查询效率(避免扫描整个表,只需要扫描相关部分即可。
在这里插入图片描述

#静态分区,导入数据时指定分区
1.先创建表,再导入数据
//根据data的值去分区,data的值是上传数据时定义的
create table t_user_part(
id int,
name string,
age int,
salary int)partitioned by (data string) row format delimited fields terminated by '\t';
也可以多层分区,只需在(data string)后加逗号继续加分区值即可,例如 (data string, data2 string),分区字段的类型除了string也可以指定其他类型,不一定都是string

#上传数据并指定分区
load data local inpath '/root/data15' into table t_user_part partition (date='15');
load data local inpath '/root/data16' into table t_user_part partition (date='16');

#单独增加分区(没有数据,了解)
alter table t_user_part add partition(day='17');
alter table t_user_part add partition(day='17') partition(day='18') ;   #增加多个分区,中间是空格

#删除分区
alter table t_user_part drop partition (day='17');
alter table t_user_part drop partition (day='17'),partition (day='18') ;  #删除多个分区,中间是,隔开
#查看分区表有多少个分区
show partitions t_user_part ;
#查看分区表结构
desc formatted t_user_part ;
#修复命令(假如在hdfs的hive表路径下创建了一个day=19文件夹,那么在hive中sql是查不出来的,
因为没有元数据,执行修复命令,可根据文件夹将元数据完善)
msck repair table t_user_part ;

select * from t_user_part  //全表数据进行的统计

select id from t_user_part where data='15' and age>20;  //查询分区为15的age>20的数据

#动态分区,导入数据时不指定固定分区,根据原数据某列/多列进行分区
2.hdfs上先有数据,再创建分区表(分区的依据是数据中的某些特定列)
set hive.exec.dynamic.partition=true;   #默认false,表示开启动态分区功能
set hive.exec.dynamic.partition.mode=nonstrick; #动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。

#创建分区表,根据city 和sdate 进行二级分区
create table t_user_part(
id int,
name string,
age int,
salary int)partitioned by (city string,sdate string) row format delimited fields terminated by '\t';

#然后将数据导入到一张临时表中(这里表名起个名字叫test.user_list_tmp),将查询结果的某个字段(也可以是多个)作为分区字段
#查询的分区字段city,sdate必须在最后,且顺序和分区表的partitioned by中的一致
insert into table t_user_part partition(city,sdate)   
select 
    t.user_id,
    t.msisdn,
    t.imsi,
    t.city,
    t.sdate
from test.user_list_tmp t;

#查看分区结果
show partitions t_user_part partition;

动态分区相关的调优参数:
#表示在所有执行 MR 的节点上,最大一共可以创建多少个动态分区,超出报错
set hive.exec.max.dynamic.partitions =1000(默认值) 
#在每个执行 MR 的节点上,最大可以创建多少个动态分区,默认是100,超出则会报错。
set hive.exec.max.dynamic.partitions.pernode=100 (默认100,一般可以设置大一点,比如1000)
#整个 MR Job 中,最大可以创建多少个 HDFS 文件,超出报错。
set hive.exec.max.created.files =10000(默认)
#当有空分区生成时,是否抛出异常。一般不需要设置。默认 false
set hive.error.on.empty.partition=false
2.4 桶表【主要用于抽样】

分桶是将数据集分解成更容易管理的若干部分的另一个技术。
分区针对的是数据的存储路径;分桶针对的是数据文件。
分桶规则:分桶字段hash值%桶的数量
分桶的数量是在创建表时指定的,数量不能更改。如果要更改数量,需要重新插入数据。

Partition:分区,用于分割数据,分割完的数据也保存在一个文件夹下;
Buckets:分桶。分桶的作用是用于分布数据,它所产生的是一个文件,不是文件夹;
Partition和Buckets的区别:分区作用于文件夹,是把文件夹下的数据进行分割,然后再分成不同的文件夹存储;
分桶作用于文件,是把一个文件内容分割成不同的部分,分别放在不同的文件中存储。
#开启分桶
set hive.enforce.bucketing=true; 

#创建分桶表,分桶字段为id(表中的某个字段),分桶个数为4个
create table t_user_buck(id int, name string)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\t';

#load方式向分桶表中导入数据
load data inpath '/student.txt' into table t_user_buck;

#select查询方式向分桶表中导入数据
insert into t_user_buck select * from t_user_temp;

注意:

  1. reduce 的个数设置为-1,让 Job 自行决定需要用多少个 reduce 或者将 reduce 的个数设置为大于等于分桶表的桶数
  2. 从 hdfs 中 load 数据到分桶表中,避免本地文件找不到问题

抽样查询

对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive 可以通过对表进行抽样来满足这个需求。
语法: TABLESAMPLE(BUCKET x OUT OF y)
注意:x 的值必须小于等于 y 的值,否则报错:

FAILED: SemanticException [Error 10061]: Numerator should not be bigger 
than denominator in sample clause for table t_user_buck 

抽样sql

select * from stu_buck tablesample(bucket 1 out of 4 on id);

bucket x out of y on id 
解释:把数据按id分为y份,从第x份开始抽样(id可以不是建表语句时的分桶依据字段,比如这里写name也可以)
2.5 临时表

表只对当前session有效,session退出后,表自动删除。
关键字:temporary

create temporary table table_name ...
修改表
#重命名表:新表名不能存在
ALTER TABLE table_name RENAME TO new_table_name ;

#更新列:注意,新列名后必须加上列类型(可以跟之前一样),不写会报错
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name col_type;

#增加和替换列
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type)
注:ADD 是代表新增一字段,字段位置在所有列后面(partition 列前),
REPLACE 则是表示替换表中所有列(假如之前有3列,替换语句中只有一列,那么替换后表就只有一列)

#删除表
drop table dept
3.数据的导入
1.基本导入(导入linux上的数据)

load data local inpath ‘local_path’ into table table_name

2.通过as关键完成数据的导入

建表的同时,通过查询导入数据
create table if not exists table_name as select id,name from t_users

3.通过查询导入数据

//使用like关键字创建t_users_like表并导入数据
create table t_users_like like t_users;
insert into table t_users_like select id,name,age,salary from t_users;

4.hdfs导入数据

load data inpath ‘hdfs_path’ into table table_name
和基本导入区别在于少个local

5.导入数据过程中数据的覆盖【了解】

load data inpath ‘hdfs_path’ overwrite into table table_name
本质 把原有表格目录的文件全部删除,再上传新的

6.通过HDFS的命令完成文件的上传【了解】

bin/hdfs dfs -put /xxxx /user/hive/warehouse/db_name.db/table_name

4.数据的导出
1.sqoop 【重点】

hadoop的一种辅助工具 HDFS/Hive <------> RDB (MySQL,Oracle)

2.insert的方式【了解】

insert overwrite [local] directory ‘/root/xiaohei’ select name from t_user;
insert overwrite [local] directory ‘/root/xiaohei’ row format delimited fields terminated by ‘\t’ select name from t_user;     //指定字段分隔符
local:导出到linux系统上,如果不带local,就是导出到hdfs上(实际也不会用,因为hive数据就在hdfs上,copy一下就可以)

3.通过HDFS的API完成文件的下载【了解】

bin/hdfs dfs -get /user/hive/warehouse/db_name.db/table_name /root/xxxx

4.命令行脚本的方式【了解】

bin/hive --database ‘db_name’ -f /root/hive.sql > /root/result    //hive.sql中写的查询语句
bin/hive --database -e ‘select * from database_tableName’ > /root/result    后面直接跟sql

5.Hive提供导入,导出的工具【了解】

1.export 导出
export table tb_name to ‘hdfs_path’

2.import 导入:hdfs_path必须是export导出的路径,hdfs随便的一个路径是不可以的
table_name 可以不存在,如果存在表中必须不能有数据
import table table_name from ‘hdfs_path’

Hive相关的配置

Hive相关的配置参数
1.hive-default.xml 默认配置
2.hive-site.xml  优先级高一级,可以覆盖hive-default.xml中的配置,未覆盖的使用hive-default.xml中的默认配置
前面已经覆盖的配置:

#替换MetaStore位置的4个和数据库相关的配置
javax.jdo.option.ConnectionURL
javax.jdo.option.ConnectionDriverName
javax.jdo.option.ConnectionUserName
javax.jdo.option.ConnectionPassword

#查询时优化显示信息(显示database)
hive.cli.print.current.db
hive.cli.print.header

3.hive启动时携带参数,优先级比配置文件高,但只用于临时调试,最后去修改配置文件重启才是最佳方案
例如:bin/hive --hiveconf hive.cli.print.current.db=false

4.启动后,修改配置,优先级更高,3一样只用于临时调试修改
set hive.cli.print.current.db   查看当前此参数的值
set hive.cli.print.current.db=true;  设置此参数的值
与mapReduce相关的配置
hadoop中的配置文件设置reduce个数:
mapred-site.xml
<property>
     <name>mapreduce.job.reduces</name>
     <value>1</value>
</property>

hive中配置文件设置reduce个数:
hive-site.xml
<!--一个reduce可以处理的数据大小≈1G-->
<property>
	  <name>hive.exec.reducers.bytes.per.reducer</name>
	  <value>1000000000</value>
</property>
<!--reduce最大个数-->
<property>
     <name>hive.exec.reducers.max</name>
     <value>999</value>
</property>

<!--在查询中是否启动MR 是如下参数配置决定的 -->
<property>
  <name>hive.fetch.task.conversion</name>
  <value>minimal</value>
  <description>
  <!--以下两个值对应的不起map、reduce的情况-->
  1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only    (select *,分区查询,limit 不起mapRedece)
  3. more    : SELECT, FILTER, LIMIT only (TABLESAMPLE, virtual columns)    (select,子查询,limit 不起mapRedece)
  </description>
</property>
Hive相关的启动参数
1. 启动hive终端时,临时设置hive的配置参数
  bin/hive --hiveconf
  
2. 启动hive时,指定启动的数据库
  bin/hive --database db_name;
  
3. 启动hive时,可以执行sql命令,执行完毕后,退出
  bin/hive -e 'sql'
  bin/hive --database db_name -e 'sql'
  例:bin/hive --database db_name -e 'select * from t_user'
  #将sql结果输出到文件中,此命令是linux中的命令  和hive无关  此时会将/root/result文件中的数据覆盖
  bin/hive --database db_name -e 'select * from t_user' > /root/result
  #将查询结果追加到文件中,不覆盖文件中原数据
  bin/hive --database db_name -e 'select * from t_user' >> /root/result
  
4. 启动hive时,如果需要执行多条sql可以把sql写在一个独立的文件里,执行完毕退出
  bin/hive -f /root/hive.sql
  #多条sql查询结果写到文件中
  bin/hive --database db_name  -f /root/hive.sql > /root/result
  bin/hive --database db_name  -f /root/hive.sql >> /root/result

外部访问hive

使用元数据服务的方式访问 Hive
  1. hive-site.xml添加配置
 <!-- 指定存储元数据要连接的地址,hive存元数据的地址,9083端口启动 -->
 <property>
	 <name>hive.metastore.uris</name>
 	<value>thrift://hadoop21:9083</value>
 </property>
  1. 启动 metastore
#是前台启动,启动后页面不能操作,需要在clone一个linux连接
bin/hive --service metastore
  1. 启动hive
bin/hive
使用 JDBC 方式访问 Hive(比如使用javaApi操纵hive)
  1. hive-site.xml添加配置
<!-- 指定 hiveserver2 连接的 host -->
<property>
	<name>hive.server2.thrift.bind.host</name>
 	<value>hadoop21</value>
</property>
<!-- 指定 hiveserver2 连接的端口号,默认端口就是10000 -->
<property>
	<name>hive.server2.thrift.port</name>
	<value>10000</value>
</property>
  1. 启动 hiveserver2
#是前台启动,启动后页面不能操作,需要在clone一个linux连接
bin/hive --service hiveserver2
  1. 启动 beeline 客户端(需要多等待一会)
 bin/beeline  -u jdbc:hive2://hadoop102:10000
  1. 看到如下界面
Connecting to jdbc:hive2://hadoop102:10000
Connected to: Apache Hive (version 3.1.2)
Driver: Hive JDBC (version 3.1.2)
Transaction isolation: TRANSACTION_REPEATABLE_READ
Beeline version 3.1.2 by Apache Hive
0: jdbc:hive2://hadoop21:10000>
hive前台启动改为后台启动
#可以看到,hive启动时有一些前台启动命令,启动后窗口就不能在使用,需要再打开一个linux窗口,
#导致可能打开多个窗口,而且窗口一旦关闭,服务就停止了,这样不行,所以将前台启动改为后台,
#既不用多个linux窗口,当关闭linux窗口时,服务也不会停止

nohup: 放在命令开头,表示不挂起,也就是关闭终端进程也继续保持运行状态
/dev/null:是 Linux 文件系统中的一个文件,被称为黑洞,所有写入改文件的内容都会被自动丢弃
2>&1 : 表示将错误重定向到标准输出上    0:键盘输入,类似java的Scanner;1:正常输出;2:错误输出(日志)
&: 放在命令结尾,表示后台运行
一般会组合使用: nohup [xxx 命令操作]> file 2>&1 &,表示将 xxx 命令运行的结果输出到 file 中,
并保持命令启动的进程在后台运行。

例如:nohup hive --service metastore > /root/metastore.log 2>&1 &
	  nohup hive --service hiveserver2 > /root/hiveserver2.log 2>&1 &

#查看HiveMetaStore和HiveServer2是否启动成功
1.看metastore.log和hiveserver2.log文件中是否有报错
2.查看进程
ps -ef | grep -v grep | grep HiveMetaStore 
ps -ef | grep -v grep | grep HiveServer2
实际jps命令也能看到两个RunJar进程,但不如ps命令看着方便(没办法区分哪个RunJar是Metastore和hiveserver2)
HiveMetastore和HiveServer2启动时报的一些错误

后来搭建Hadoop和hive环境时,报了一些错(可能是因为写此博客之前用的版本太老了),这里介绍一下遇到的错误和解决办法
Hadoop版本:2.8.5;hive版本:2.3.8;mysql版本:5.7.2
hive的lib包中需要上传mysql驱动,在maven库中未找到5.7.2版本的驱动,百度了下,有博客说可以使用8.0版本驱动和5.1版本的,这里我选择了5.1.47的驱动jar包

mysql5.7.11对应的JDBC驱动是5.1版本。
mysql 5.7 用8.0版本的驱动可以,5.1版本也可以,5.5、5.6、5.7都不可以。
MySQL Connectors 官方文档 上面只有version8.0和version5.1两个版本的文档
version8.0文档上有说明:Connector/J 8.0 provides compatibility with all the functionality of MySQL 5.5, 5.6, 5.7, and 8.0表示兼容。

启动metastore时报的错
错误一:

MetaException(message:Version information not found in metastore. )
        at org.apache.hadoop.hive.metastore.RetryingHMSHandler.<init>(RetryingHMSHandler.java:83)
        at org.apache.hadoop.hive.metastore.RetryingHMSHandler.getProxy(RetryingHMSHandler.java:92)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.newRetryingHMSHandler(HiveMetaStore.java:6896)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.newRetryingHMSHandler(HiveMetaStore.java:6891)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:7149)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:7076)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:226)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:141)

解决办法:
在hive-site.xml配置文件中添加如下配置:

<property>
 	<name>datanucleus.metadata.validate</name>
	<value>false</value>
</property>
<property>
 	<name>hive.metastore.schema.verification</name>
 	<value>false</value>
</property>

错误二:

MetaException(message:Required table missing : "`DBS`" in Catalog "" Schema "". DataNucleus requires this table to perform its persistence operations. Either your MetaData is incorrect, or you need to enable "datanucleus.schema.autoCreateTables")
	at org.apache.hadoop.hive.metastore.RetryingHMSHandler.<init>(RetryingHMSHandler.java:84)
	at org.apache.hadoop.hive.metastore.RetryingHMSHandler.getProxy(RetryingHMSHandler.java:93)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.newRetryingHMSHandler(HiveMetaStore.java:8661)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.newRetryingHMSHandler(HiveMetaStore.java:8656)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:8926)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:8843)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.hadoop.util.RunJar.run(RunJar.java:226)
	at org.apache.hadoop.util.RunJar.main(RunJar.java:141)

解决办法:
在此环境中,hive的元数据保存在远程的mysql中,所以该错误意思是:在远程的数据库中没有找到相应的数据对象。
在hive-site.xml配置文件中添加如下配置:

<!--当元数据库中必要的数据对象不存在时,会自动创建。-->
<property>
	<name>datanucleus.schema.autoCreateAll</name>
	<value>true</value>
</property>

错误三:

org.apache.thrift.transport.TTransportException: Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083.
	at org.apache.thrift.transport.TServerSocket.<init>(TServerSocket.java:109)
	at org.apache.thrift.transport.TServerSocket.<init>(TServerSocket.java:91)
	at org.apache.thrift.transport.TServerSocket.<init>(TServerSocket.java:87)
	at org.apache.hadoop.hive.metastore.utils.SecurityUtils.getServerSocket(SecurityUtils.java:253)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:8968)
	at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:8843)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.hadoop.util.RunJar.run(RunJar.java:318)
	at org.apache.hadoop.util.RunJar.main(RunJar.java:232)
Caused by: java.net.BindException: Address already in use (Bind failed)
	at java.net.PlainSocketImpl.socketBind(Native Method)
	at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
	at java.net.ServerSocket.bind(ServerSocket.java:375)
	at org.apache.thrift.transport.TServerSocket.<init>(TServerSocket.java:106)
	... 11 more

解决办法:
此问题是启动metastore有报错,但进程还在,被占用着,使用jps然后把RunJar进程杀掉即可

[root@slave2 bin]# jps
132562 Jps
77728 SecondaryNameNode
78951 NodeManager
77432 DataNode
78843 ResourceManager
122029 RunJar
77311 NameNode
122030 RunJar

[root@slave2 bin]# kill -9  122029 122030 

错误四:

WARN: Establishing SSL connection without server's identity verification is not recommended. 
According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set.
For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. 
You need either to explicitly disable SSL by setting useSSL=false, 
or set useSSL=true and provide truststore for server certificate verification.

解决办法:
在hive-site.xml的javax.jdo.option.ConnectionURL属性后加上useSSL=false
注意:hive-site.xml中url里参数分隔符&需要转义为 &amp; 才行;如果需要用&连接useSSL=false不能直接用&,要进行转义&amp;,否则报错 The reference to entity "useSSL" must end with the ';' delimiter

<property>
	<name>javax.jdo.option.ConnectionURL</name>
	<value>jdbc:mysql://slave2:3306/metastore?createDatabaseIfNotExist=true&amp;useSSL=false</value>
	<description>the URL of the MySQL database</description>
</property>
hive 服务启动脚本(metastore、hiveserver2 )
#将命令写在hive的bin目录的hiveservices.sh文件中
vim $HIVE_HOME/bin/hiveservices.sh
#!/bin/bash
HIVE_LOG_DIR=$HIVE_HOME/logs
if [ ! -d $HIVE_LOG_DIR ]
then
	mkdir -p $HIVE_LOG_DIR
fi
#检查进程是否运行正常,参数 1 为进程名,参数 2 为进程端口
function check_process()
{
	pid=$(ps -ef 2>/dev/null | grep -v grep | grep -i $1 | awk '{print $2}')
	ppid=$(netstat -nltp 2>/dev/null | grep $2 | awk '{print $7}' | cut -d '/' -f 1)
	echo $pid
	[[ "$pid" =~ "$ppid" ]] && [ "$ppid" ] && return 0 || return 1
}

function hive_start()
{
	metapid=$(check_process HiveMetaStore 9083)
	cmd="nohup hive --service metastore >$HIVE_LOG_DIR/metastore.log 2>&1 &"
	[ -z "$metapid" ] && eval $cmd || echo "Metastroe 服务已启动"
	server2pid=$(check_process HiveServer2 10000)
	cmd="nohup hiveserver2 >$HIVE_LOG_DIR/hiveServer2.log 2>&1 &"
	[ -z "$server2pid" ] && eval $cmd || echo "HiveServer2 服务已启动"
}

function hive_stop()
{
	metapid=$(check_process HiveMetaStore 9083)
	[ "$metapid" ] && kill $metapid || echo "Metastore 服务未启动"
	server2pid=$(check_process HiveServer2 10000)
	[ "$server2pid" ] && kill $server2pid || echo "HiveServer2 服务未启动"
}

case $1 in
"start")
	hive_start
	;;
"stop")
	hive_stop
	;;
"restart")
	hive_stop
	sleep 2
	hive_start
	;;
"status")
	check_process HiveMetaStore 9083 >/dev/null && echo "Metastore 服务运行正常" || echo "Metastore 服务运行异常"
	check_process HiveServer2 10000 >/dev/null && echo "HiveServer2 服务运行正常" || echo "HiveServer2 服务运行异常"
	;;
*)
	echo Invalid Args!
	echo 'Usage: '$(basename $0)' start|stop|restart|status'
	;;
esac

给hiveservices.sh文件添加执行权限

 chmod +x $HIVE_HOME/bin/hiveservices.sh

使用脚本启动

 hiveservices.sh start
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值