* Hive框架基础(二)
我们继续讨论hive框架
* Hive的外部表与内部表
内部表:hive默认创建的是内部表
例如:
create table table001 (name string , age string) location '/input/table_data';
此时:会在HDFS上新建一个table001表的数据存放地
接着执行:
load data inpath'/input/data 'into table table001;(注意,load关键字后没有跟local关键字)
** 会将hdfs上的/input/data目录下的数据转移到/input/table_data目录下
** 如果删除table001表,会将table001表的数据和元数据信息全部删除,即最后/input/table_data下无数据
** 由于此处load是将HDFS中的数据移到HDFS另一个 目录,所以,/input/data中的数据已经删除。
** 如果创建内部表时没有指定location,就会在/user/Hive/warehouse/下新建一个表目录
外部表:默认创建的不是外部表,需要使用external关键字标识
例如:
create external table etable001(name string, age string);
会在/user/hive/warehouse/新建一个表目录et
接着执行:
load data inpath '/input/edata' into table etable001;(注意,load关键字后没有跟local关键字)
** 把hdfs上/input/edata/下的数据转到/user/hive/warehouse/et下
** 删除这个外部表后,/user/hive/warehouse/et下的数据不会删除
** 由于此处load是将HDFS中的数据移到HDFS另一个 目录,所以,/input/data中的数据已经删除。(和内部表的操作情况一致)
总结:
** 外部表中的数据并不是由它自己来管理,而内部表则不一样;
** 在删除内部表的时候,Hive将会把属于表的元数据和数据全部删掉;而删除外部表的时候,Hive仅仅删除外部表的元数据,数据是不会删除的。
** 在创建内部表或外部表时加上location的效果是一样的,只不过表目录的位置不同而已,加上partition用法也一样,只不过表目录下会有分区目录而已(后续会讲到)
** load data local inpath直接把本地文件系统的数据上传到HDFS上,如果指定了location,则上传到指定位置,没有的话上传到hive默认配置的数据仓库中。
** 外部表相对来说更加安全,数据组织也更加灵活,方便共享源数据。
* Hive分区表
** 创建表的时候只需要指定分区字段,分区范围是在加载数据的时候才指定的
** 对大表数据进行分类存储,提高数据安全性
** 使用分区表能大大的提高查询效率
** 创建分区表
此部分直接举例说明,讲解这部分知识涉及到的例子所需要用到的数据材料请到传送门下载:
链接:http://pan.baidu.com/s/1dFCFuSD 密码:fc41
create database if not exists db_web_data ;
create table if not exists db_web_data.track_log(
id string,
url string,
referer string,
keyword string,
type string,
guid string,
pageId string,
moduleId string,
linkId string,
attachedInfo string,
sessionId string,
trackerU string,
trackerType string,
ip string,
trackerSrc string,
cookie string,
orderCode string,
trackTime string,
endUserId string,
firstLink string,
sessionViewNo string,
productId string,
curMerchantId string,
provinceId string,
cityId string,
fee string,
edmActivity string,
edmEmail string,
edmJobId string,
ieVersion string,
platform string,
internalKeyword string,
resultSum string,
currentPage string,
linkPosition string,
buttonPosition string
)
partitioned by (date string,hour string)
row format delimited fields terminated by ' ';
字段设计缘由请参看字典:
将以上文本包含的sql命令保存到p2.hql文件中,然后使用命令:
$ bin/hive -f hqlDir/p2.hql,如图:
** 加载数据
首先将“2015082818”和“2015082819”两个文件考入到/home/z/Desktop目录下
使用命令:
hive (default)> load data local inpath '/home/z/Desktop/2015082818' into table db_web_data.track_log partition(date='20150828',hour='18');
hive (default)> load data local inpath '/home/z/Desktop/2015082819' into table db_web_data.track_log partition(date='20150828',hour='19');
** 查询数据
hive (default)> select * from db_web_data.track_log where date='20150828' ;
hive (default)> select * from db_web_data.track_log where date='20150828' and hour='18';
(这里由于数据量太大,就不给大家截图展示了)
拓展:
查看一个分区表有几个分区
hive (db_web_data)> show partitions track_log ;
删除一个分区表的分区
hive (db_web_data)> alter table track_log drop partition(date='xxxx',hour='xxxx') ;
* Hive创建表的方式
** 方案一
即创建一个空表,例如之前我们一直用到的方式。
** 方案二
即把一张表的某些字段抽取出来,创建成一张新表
例如:
create table db_web_data.backup_track_log as select * from db_web_data.track_log;
** 方案三
复制表结构
尖叫提示:以上创建表的过程均可以使用location指定创建位置,也可以不指定。
例如:
create table db_web_data.like_track_log like db_web_data.track_log;
* Hive表导入数据方式
** 方案一
加载本地文件到Hive表
load data local inpath 'path/file' into table 表名称 ;
** 方案二
加载HDFS文件到HIVE表(即方案2没有local关键字)
load data inpath 'path/file' into table 表名称 ;
** 方案三
加载数据覆盖表中已有的数据
load data local inpath 'path/file' overwrite into table 表名称 ;
** 方案四
创建表时通过select加载
create table db_web_data.track_log_as as select * from db_web_data.track_log;
** 方案五
用insert命令加载
*** 应用场景:把用select命令分析的结果写入某个临时表
*** append 追加写入 --默认
*** overwrite 覆盖写入 --使用最多
--先要创建好表,然后再写入数据
insert into table 表名 select * from db_web_data.track_log;
insert overwrite table 表名 select * from db_web_data.track_log;
* Hive表导出数据方式
** 方案一
insert...local diretory导出到本地
例如:
insert overwrite local directory "/home/z/Desktop/backup" row format delimited fields terminated by ' ' select * from staff ;
** 方案二
insert..diretory导出到HDFS
例如:
insert overwrite diretory "path/" select * from staff;
** 方案三
直接在linux段,使用hive -e命令执行hql语句
例如:
$ bin/hive -e "select * from staff;" > /home/z/backup.log
** 方案四
sqoop工具(后面讨论)
* Hive语句基本拓展
** 查询具体的某个某些字段
例如:
select name, sex from staff;
** where
select * from staff where name='隔壁老王';
注:where 条件可以是分区字段
** limit
select * from track_log limit 1 ;
** distinct 去重
select distinct(name) from staff ;
** < > = >= <= !=
select * from staff where id > 5000 ;
** and 、between ... and ... 、 not in 、in
** like % _
** + - * /
以上各种运用详细可以参考sql语法
* Hive 常用函数
** 查看有哪些函数
hive (default)> show functions;
** 查看具体某个函数的用法
hive (default)> desc function extended max ;
** 常用函数一些用法
假设情景:我们有如下两个表,分别是员工信息表emp和部门信息表dept,表内容如下图:
emp:
字段:empno int, ename string, job string, mgr int, hiredate string, sal double, comm double, deptno int
字段对应数据:
dept:
字段:deptno int, dname string, loc string
字段对应数据:
请自行创建数据库:
db_emp_dept
以及对应表:
emp、dept
并导入数据
链接:http://pan.baidu.com/s/1qY8pjTq 密码:54w6
最终如图:
以上面的情景,解释下面的函数:
*** 最大值统计函数: max
语法: max(col)
返回值: double
说明:统计结果集中col字段的最大值
例如:显示每个部门最高薪资
select deptno,max(sal) from emp group by deptno ;
结果如图:
例如:显示部门名称, 部门最高薪资
select max(b.dname),max(sal) from emp a inner join dept b on a.deptno = b.deptno group by a.deptno ;
结果如图:
或者:select b.dname,max(sal) from emp a inner join dept b on a.deptno = b.deptno group by a.deptno,dname ;
结果如图:
*** 最小值统计函数: min
语法:min(col)
返回值::double
说明:统计结果集中col字段的最小值
例如:显示部门名称, 部门最高薪资, 部门所在的城市
select max(dname),max(sal),min(loc) from emp inner join dept on emp.deptno = dept.deptno group by emp.deptno ;
结果如图:
*** 平均值统计函数: avg
语法: avg(col), avg(DISTINCT col)
返回值: double
说明: avg(col)统计结果集中col的平均值;avg(DISTINCT col)统计结果中col不同值相加的平均值
例如:请参照前文内容,自行测试
*** 总和统计函数: sum
语法: sum(col), sum(DISTINCT col)
返回值: double
说明: sum(col)统计结果集中col的相加的结果;sum(DISTINCT col)统计结果中col不同值相加的结果
例如:请参照前文内容,自行测试
*** 个数统计函数: count
语法: count(*), count(expr), count(DISTINCT expr[, expr_.])
返回值: int
说明: count(*)统计检索出的行的个数,包括NULL值的行;count(expr)返回指定字段的非空值的个数;count(DISTINCTexpr[, expr_.])返回指定字段的不同的非空值的个数
例如:请参照前文内容,自行测试
*** 取随机数函数: rand
语法: rand(),rand(int seed)
返回值: double
说明:返回一个0到1范围内的随机数。如果指定种子seed,则会等到一个稳定的随机数序列
例如:select rand();
*** 字符串连接函数:concat
语法: concat(string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,支持任意个输入字符串
例如:select concat(empno,"_",ename) from emp ;
结果如图:
*** 字符串截取函数:substr
语法: substr(string A, int start, int end)
返回值: string
说明:返回字符串A从start位置到结尾end的字符串,end不填写,则默认为末尾。
例如:select substr(hiredate,1,4) from emp ;(请自行去掉4,再试一次,即可明白)
结果如图:
*** 字符串转大写函数:upper
语法: upper(string A)
返回值: string
说明:返回字符串A的大写格式
*** 字符串转小写函数:lower
语法: lower(string A)
返回值: string
说明:返回字符串A的小写格式
*** 日期转天函数: day
语法: day (string date)
返回值: int
说明:返回日期中的天。
例如:select day(hiredate) from emp ;
结果如图:
*** 日期转小时函数: hour
语法: hour (string date)
返回值: int
说明:返回日期中的小时。
例如:select hour("2016-09-01 12:34:34") ;
*** 日期转分钟函数: minute
语法: minute (string date)
返回值: int
说明:返回日期中的分钟。
*** 日期转秒函数: second
语法: second (string date)
返回值: int
说明:返回日期中的秒。
*** 日期转UNIX时间戳函数:unix_timestamp
语法: unix_timestamp(string date)
返回值: bigint
说明:转换格式为"yyyy-MM-ddHH:mm:ss"的日期到UNIX时间戳。如果转化失败,则返回0。
举例:
select unix_timestamp("2018-07-07 12:34:34") ;
select unix_timestamp('2011-12-07 13:01:03') from table;
*** UNIX时间戳转日期函数:from_unixtime
语法: from_unixtime(bigint unixtime[, string format])
返回值: string
说明:转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式
例如:
select from_unixtime(1472704474) ;
select from_unixtime(1472704474,'yyyyMMdd') from table;
*** 类型转换函数:cast
类型转换函数: cast
语法: cast(expr as )
返回值: Expected "=" to follow "type"
说明:返回array类型的长度
例如:select cast(1472704474123/1000 as int) ;
*** 条件判断函数:CASE
语法: CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END
返回值: T
说明:如果a为TRUE,则返回b;如果c为TRUE,则返回d;否则返回e
例如:
> select ename,sal+comm from emp ;
hive (db_emp_dept)> select ename,
> case when comm is null then 0+sal
> else comm+sal end
> from emp ;
hive (db_emp_dept)> select ename,
> case when sal<1000 then "lower"
> when sal>=1000 and sal<=2000 then "pass"
> when sal>2000 then "high"
> else "OK" end
> from emp ;
hive (db_emp_dept)> select ename,
> case when sal<1000 then deptno
> when sal>=1000 and sal<=2000 then comm
> else null end
> from emp ;
对于语法不了解的,请移步:SQL基础
* Hive explain 解析执行计划
hive是把sql语句翻译成mapreduce任务来执行的,那么具体mapreduce是怎么一个执行结构,可以在sql前面加上explain关键字来查看。
例如:
explain select count(distinct(deptno)) from emp ;
* Hive 设定哪些语句执行mapreduce运算
参数名:hive.fetch.task.conversion
参数值:minimal或者more
从Hive 0.10.0版本开始,对于简单的不需要聚合的语句,比如select <clo> from <table> limit n这样的语句,根本不需要启动mapreduce job,直接通过fetch task即可获取数据,那么此时,我们就配置这个属性的值为more即可。可以查看对应的官方解释如下:
配置后如图:
* 配置HiveServer2服务
启动Hive有如下几种方式:
1、 hive 命令行模式
进入hive安装目录,输入bin/hive的执行程序,或者输入 hive –service cli
用于linux平台命令行查询,查询语句基本跟sql查询语句类似
2、hive web界面的启动方式,没什么用
3、hive 远程服务 (端口号10000) 启动方式
bin/hive –service hiveserver2
用java,python等程序实现通过jdbc等驱动的访问hive。
** 配置hive-site.xml
属性:hive.server2.thrift.port,值:10000
属性:hive.server2.thrift.bind.host,值:z01
属性:hive.server2.long.polling.timeout,值:5000(注意,此处去掉默认带有的L)
此处就不再配图了。
** 检查端口
首先,检查10000端口是否被占用:
$ netstat -antp|grep 10000
如果被占用,使用kill -9 <pid>杀掉
** 启动服务
$ bin/hive --service hiveserver2
注意:service前面有两个“-”
** 连接服务
$ bin/beeline
beeline> help
> !connect jdbc:hive2://z01:10000
(注意:此处如果直接敲回车,不使用用户登录,那么默认为匿名登录,用户名为:anonymous,无密码)
(注意:在我这里,我也可以使用z这个用户名登录,密码是我自己的密码)
> select * from db_emp_dept.emp ;
如图:
注意,如果需要执行Job任务,则:
首先修改该属性
hive.server2.enable.doAs:false
解释:改属性为true时,启动hiveServer2的用户为当前默认用户,访问Hadoop则也用该用户。
如果为false,则beeline中登录的是哪个用户,就用哪个用户,这里我的环境中,可以使用“z”这个用户。
这样一来,才能成功在hiveServer2中提交并运行Job任务。
* UDF
即:user defined function
UDF函数开发要点:
** 必须继承UDF类
** 重写evaluate函数
** 必须要有返回类型,可以返回null,但是返回类型不能为void
** 建议使用Text/LongWritable
** 环境配置
1、在eclipse中创建一个maven项目,并修改pom依赖包,添加如图所示内容:
2、上传repository.tar.gz,并解压到/home/z/.m2/
3、修改maven的配置文件
$ vi /opt/modules/apache-maven-3.0.5/conf/settings.xml
在mirrors标签中加入如下内容:
接着,将该文件拷贝到.m2目录下:
$ cp settings.xml /home/z/.m2/
4、更新maven工程
在eclipse中右键项目,选择maven-update project即可。
** 编写并使用UDF
*** 例如我们编写一个UDF函数,用来将制定字段内容转换为小写:
*** 将程序打成jar包后,导入该jar
hive (default)> add jar /home/z/Desktop/lower.jar;
*** 创建临时函数:
hive (default)> create temporary function my_lower as 'com.z.demo.udf.Lower';
*** 使用该函数
hive (default)> show fuctions ;
hive (default)> select my_lower(ename) from db_emp_dept.emp;
*** 注意事项:
**** 以上方式添加的UDF函数是临时生效的,只要退出当前hive窗口,便失效,一般不会设置永久生效。
**** 实际应用中,Hive会有多个Job任务,每个job任务都有自己对应的函数、以及hql语句; 每个job任务增加函数的语句和具体的业务分析语句一般会把它放到一个文件中(比如:job01.hql、job02.hql、job03.hql),然后使用bin/hive -f job1.hql方式执行即可。
* 自动化脚本-加载本地目录的指定数据到HDFS
脚本如下:
对应的auto.hql文件中的内容如下:
* 总结
本节主要讲解hive的一些高级用法,以及如何开发自定义函数用使用。
个人微博:http://weibo.com/seal13
QQ大数据技术交流群(广告勿入):476966007
作者:Z尽际
链接:https://www.jianshu.com/p/4c105383b959
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。