Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
-
External Table 只有一个过程,加载数据和创建表同时完成(CREATE EXTERNAL TABLE ……LOCATION),实际数据是存储在 LOCATION 后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个 External Table 时,仅删除元数据,表中的数据不会真正被删除。
基本数据类型
集合数据类型
分区表
hive的出现
-》Facebook公司,开源了hive框架,提示了SQL on Hadoop概念
-》在Hadoop上运行SQL语句
-》简化开发过程中的操作,提高效率
-》与传统数据分析结合,使用数据库表格的形式去分析数据
-》将数据文件映射成表
hive的架构介绍
1、官网http://hive.apache.org/
2、hive是基于Hadoop之上的,依赖Hadoop,文件是存储在HDFS上的,底层运行的是MR程序
3、功能:就是将SQL语句转换成底层运行的MR程序执行
-》可以理解为底层封装了一个非常高级的MR程序模板
-》将SQL解析成MR或者多个MR进行处理
4、sql on Hadoop类型的框架
-》presto底层是在内存跑的
-》impala-》dremel
-》spark sql
hive的安装部署
1、由于hive是依赖于Hadoop的,所以先把Hadoop相关的服务启动(HDFS、YARN)
2、配置
-》解压
bin/hdfs dfs -mkdir /tmp
bin/hdfs dfs -mkdir /user/hive/warehouse
bin/hdfs dfs -chmod g+w /tmp
bin/hdfs dfs -chmod g+w /user/hive/warehouse
-》创建一个文件夹用于保存hive的所有数据,便于管理
4、元数据默认情况下是存储在derby数据库中的
5、hive在HDFS上的默认存储路径
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
<description>location of default database for the warehouse</description>
</property>
6、修改hive-env.sh,注意改名
# Set HADOOP_HOME to point to a specific hadoop install directory
HADOOP_HOME=/opt/moduels/hadoop-2.5.0
# Hive Configuration Directory can be controlled by:
export HIVE_CONF_DIR=/opt/moduels/hive-0.13.1-bin/conf
7、启动hive
$ bin/hive
8、常用语句
查看数据库列表 show databases;
查看数据库定义 describe database hadoop;
建数据库create database if not exists hadoop;
进入数据库use hadoop;
查看数据库表列表 show tables;
查看表结构 describe student;
建表
create table if not exists student(
num int,
name string
)
row format delimited fields terminated by'\t';
指定分隔符
加载数据 local 表明数据来源于本地 Linux 系统 不加表明数据来源于hdfs文件系统;
load data local inpath '/opt/datas/student.txt' into table student;
查询数据select * from student;
hive的存储结构
仓库目录 数据库目录 表目录 数据文件
/user/hive/warehouse /hadoop.db/student/student.txt
如果是直接在default数据库下建表的话就是这样的结构,/user/hive/warehouse代表默认数据库位置
/user/hive/warehouse /student/student.txt
hive 2.0之后加入了内存的概念,查询的速度有所提升
六、配置mysql数据库以及元数据
1、Derby数据库只能起一个实例 这是 用MySql作为元数据库的重要原因
2、安装mysql
-》查询系统中没有mysql
$ sudo rpm -qa | grep mysql
-》卸载自带的mysql库
$ sudo rpm -e --nodeps mysql-libs-5.1.66-2.el6_3.x86_64
-》使用yum进行mysql的安装
$ sudo yum -y install mysql-server
-》查看mysqld服务是否开启
$ sudo service mysqld status
-》启动服务
$ sudo service mysqld start
-》设置开机启动mysqld
$ sudo chkconfig mysqld on
3、设置mysql管理员root的密码
mysqladmin -u root password '123456'
-》进入mysql
$ mysql -uroot -p
4、设置mysql链接的权限
-》修改mysql数据库中的user表
select user,host from user;
-》在删除之前先插入一条数据
grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option;
*.* -》 Hadoop.student
-》删除表中的信息
mysql> delete from user where host='127.0.0.1';
Query OK, 1 row affected (0.00 sec)
mysql> delete from user where host='bigdata-01.yushu.com';
Query OK, 2 rows affected (0.00 sec)
mysql> delete from user where host='localhost';
Query OK, 2 rows affected (0.00 sec)
-》刷新并退出mysql
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> quit;
Bye
-》建议重启mysqld的服务
$ sudo service mysqld restart
5、自定义hive的配置文件,从默认的文件拷贝一份过来,然后删除内容
$ cp hive-default.xml.template hive-site.xml
可以使用vi快捷键快速删除,**dd多行删除所有配置内容,除了文件头
6、修改hive-site.xml
指定连接mysql数据库的主机名称以及端口号,还有新建数据库的名称
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://bigdata-01.yushu.com:3306/metastore?createDatabaseIfNotExist=true</value>
</property>
指定mysql的链接驱动
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
指定mysql的登录用户名和密码
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>123456</value>
</property>
拷贝mysql驱动包到hive的lib目录下
$ cp -r mysql-connector-java-5.1.27-bin.jar /opt/moduels/hive-0.13.1-bin/lib/
Linux下的mysql的一些路径位置:
mysql数据库文件的存放路径:/var/lib/mysql/
mysql可执行的脚本存放路径:/usr/bin/mysql
mysql配置文件: /etc/my.cnf
七、hive的数据库和表的基本操作
1、数据库的两类操作
DML 数据控制语言
DDL 数据定义语言
建库:
create database if not exists dbname;
使用进入数据库:
use dbname;
删除
drop
建表:MANAGED_TABLE (默认是管理表也叫外部表)
create table if not exists student(
num int,
name string
)
row format delimited fields terminated by'\t';
stored as textfile;
默认存储格式为:textfile
select * 不会运行MR
select 字段会运行MR
描述一张表,三种方式
desc student;
desc extended student;
desc formatted student;----格式比较好看
函数方法
show functions;查看系统中的方法
desc function upper;
desc function extended upper;
注意描述一个方法,需要加上function关键词,与描述表进行区分
hive自定义日志log文件
1、对hive下的conf目录下的mv hive-log4j.properties.template hive-log4j.properties重命名
2、修改hive.log.dir=/opt/moduels/hive-0.13.1-bin/logs,指定自定义的log路径
-》注意先创建,默认是在/tmp/***用户名下
hive指定数据库名和列名
1、修改hive-site.xml文件
-》指定显示列名
<property>
<name>hive.cli.print.header</name>
<value>true</value>
</property>
-》指定显示数据库名
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
</property>
hive的常用shell参数
使用bin/hive -help查看参数
1、指定默认链接的数据库
$ bin/hive --database hadoop
2、在linuxshell命令行执行HQL语句
$ bin/hive -e 'show databases'
$ bin/hive -e 'show databases' > hivetest.txt 清空内容写入 >>文章末尾追加写入
将结果重定向到一个指定的文件中,使用追加或者覆盖符号
3、在linuxshell命令行执行一个写有sql语句的文件
$ bin/hive -f /opt/datas/hive.sql
4、只针对于当前shell生效的更改配置的参数
$ bin/hive --hiveconf hive.cli.print.current.db=false
5、查看当前参数的设置的值是什么
set hive.cli.print.current.db;
set hive.cli.print.current.db=false;
同样也可以更改当前参数的值,只针对于当前shell生效
!ls /; 查看Linux本地文件系统根目录
dfs -ls /; 查看hdfs本地文件系统根目
开启Hive的元数据服务
--》bin/hive --service metastore
hive数据库的常用操作
1、LOCATION指定数据库表的位置
建库:
create database if not exists db01_loc LOCATION '/locate';
建表:
create table db01_loc.tb01(
name string
)row format delimited fields terminated by '\t';
2、不指定位置按配置文件的路径设置
建库:
create database if not exists db02;
删除数据库:
drop database db02;
DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE];
drop database db01_loc CASCADE;-----删除非空的数据库
hive的表的常用操作:
表的第一种创建方式:普通创建
create table if not exists stu_info(
num int,
name string
)
row format delimited fields terminated by '\t'
stored as textfile;
load data local inpath '/opt/datas/student.txt' into table stu_info;------加上 local关键字代表从本地 Linux系统复制数据至表上。
truncate table student;------清空表的内容,保留了表的结构
删除表:
drop table if exists student;
create table if not exists student(
num int,
name string
)
row format delimited fields terminated by '\t'
stored as textfile;
从本地加载
load data local inpath '/opt/datas/student.txt' into table student;
hive客户端上传文件到hdfs文件系统 dfs -put /opt/datas/students /;
从HDFS加载
load data inpath '/student.txt' into table student;
本地加载和HDFS加载的区别,一个本地的复制拷贝,一个是移动数据文件的位置到对应的表目录下
表的第二种创建方式:子查询
create table stu_as as select name from student;
特点:将子查询的结构数据赋予一张新的表
表的第三种创建方式:like方式
create table stu_like like student;
特点:复制表的结构
建库:
create database if not exists db_emp;
员工表:
create table emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
row format delimited fields terminated by '\t';
load data local inpath '/opt/datas/emp.txt' into table emp;
load data local inpath '/opt/datas/emp.txt' overwrite into table emp;
先删除数据,后加载数据
部门表:
create table dept(
deptno int,
dname string,
loc string
)
row format delimited fields terminated by '\t';
load data local inpath '/opt/datas/dept.txt' into table dept;
hive的外部表
1、EXTERNAL-》外部表,另一种表的类型
2、举例:
Web服务器-》生成大量日志文件
-》20170513.log文件
情况:多个部门要分析多个不同的指标,建不同的表,但分析的数据源文件只有一份
create table emp1(--普通表
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
row format delimited fields terminated by '\t'
LOCATION '/user/hive/warehouse/db_emp.db/emp';
load data local inpath '/opt/datas/emp.txt' into table emp;
show tables;->mysql找table
如果没有列出表,说明表的元数据被删除了,然后再删除表的文件夹
创建外部表:
create EXTERNAL table dept_ext(
deptno int,
dname string,
loc string
)
row format delimited fields terminated by '\t'
LOCATION '/user/hive/warehouse/db_emp.db/dept';
管理表删除的时候是删除元数据和表的对应文件夹
外部表删除的时候只删除元数据
首先创建管理表,然后可以创建多个外部表
作用:保证数据的安全性
八、hive中的分区表
举例:
-》先查询再过滤
WEB服务器,存储日志文件,分析
-》logs文件夹
-》20170513.log
-》20170514.log
-》20170515.log
-》20170516.log
使用hive去分析前一天的数据
第一种方式:将所有的日志文件放到一个文件夹下,使用一张表进行加载
在hive输入SQL-》找到元数据-》找到table以及找到HDFS上table对应的文件夹
-》将文件夹中的数据返回-》封装给MR
select * from logs where date='20170513';
-》直接加载,hive中的分区概念
WEB服务器,存储日志文件,分析
-》logs文件夹
-》20170513文件夹
-》20170513.log
-》20170514文件夹
-》20170514.log
-》20170515文件夹
-》20170515.log
-》20170516文件夹
-》20170516.log
select * from logs where date='20170513';
创建分区表:分区表的分区是虚拟逻辑的
create table emp_part(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
partitioned by (date string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/datas/emp.txt' into table emp_part partition (date='20170513');
load data local inpath '/opt/datas/emp.txt' into table emp_part partition (date='20170512');
select * from emp_part where date='20170513';
-》logs文件夹
-》20170513文件夹
-》20170513.log
-》20170514文件夹
-》20170514.log
-》20170515文件夹
-》20170515.log
-》20170516文件夹
-》20170516.log
create table emp_part3(--多级分区
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
partitioned by (date string,hour string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/datas/emp.txt' into table emp_part3 partition (date='20170513',hour='10');
load data local inpath '/opt/datas/emp.txt' into table emp_part3 partition (date='20170513',hour='11');
分区的方式:动态分区
<property>
<name>hive.exec.dynamic.partition</name>
<value>true</value>
<description>Whether or not to allow dynamic partitions in DML/DDL.</description>
</property>
-》默认值是true,代表允许使用动态分区实现
<property>
<name>hive.exec.dynamic.partition.mode</name>
<value>strict</value>
<description>In strict mode, the user must specify at least one static partition in case the user accidentally overwrites all partitions.</description>
</property>
-》set hive.exec.dynamic.partition.mode=nonstrict; 使用非严格模式
建表:
create table yhd_part2(
id string,
url string,
guid string
)
partitioned by (date string,hour string)
row format delimited fields terminated by '\t';
执行动态分区:
insert into table yhd_part2 partition (date,hour) select * from yhd_qingxi;
-》也可以不写select * ,但是要写全字段
-》首先根据select * 找到表,按照里面的字段date hour进行匹配
作用:提高查询检索的效率
九、分析函数&窗口函数
作用:对分组后的数据进行处理
create table emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
row format delimited fields terminated by '\t';
load data local inpath '/opt/datas/emp.txt' into table emp;
需求:查看部门10的所有员工,按照薪资进行降序排列,默认情况下是升序的
select * from emp where deptno='10' order by sal desc;
emp.empno emp.ename emp.job emp.mgr emp.hiredate emp.sal emp.comm emp.deptno
7839 KING PRESIDENT NULL 1981-11-17 5000.0 NULL 10
7782 CLARK MANAGER 7839 1981-6-9 2450.0 NULL 10
7934 MILLER CLERK 7782 1982-1-23 1300.0 NULL 10
需求:按照所有部门进行分组,按照薪资进行降序排列,最后一列展示该部门的最高薪资
select empno,ename,deptno,sal,max(sal) over (partition by deptno order by sal desc) as max_as from emp;
(partition by deptno order by sal desc)这部分进行了分组,然后针对每个分组进行排序
如果不使用这种分析函数之类的去分析的话,排序和分组都是全局的
empno ename deptno sal max_as
7839 KING 10 5000.0 5000.0
7782 CLARK 10 2450.0 5000.0
7934 MILLER 10 1300.0 5000.0
7788 SCOTT 20 3000.0 3000.0
7902 FORD 20 3000.0 3000.0
7566 JONES 20 2975.0 3000.0
7876 ADAMS 20 1100.0 3000.0
7369 SMITH 20 800.0 3000.0
7698 BLAKE 30 2850.0 2850.0
7499 ALLEN 30 1600.0 2850.0
7844 TURNER 30 1500.0 2850.0
7654 MARTIN 30 1250.0 2850.0
7521 WARD 30 1250.0 2850.0
7900 JAMES 30 950.0 2850.0
----按照部门分组对薪资高低排名
select empno,ename,deptno,sal,row_number() over (partition by deptno order by sal desc) as rn from emp;
empno ename deptno sal rn
7839 KING 10 5000.0 1
7782 CLARK 10 2450.0 2
7934 MILLER 10 1300.0 3
7788 SCOTT 20 3000.0 1
7902 FORD 20 3000.0 2
7566 JONES 20 2975.0 3
7876 ADAMS 20 1100.0 4
7369 SMITH 20 800.0 5
7698 BLAKE 30 2850.0 1
7499 ALLEN 30 1600.0 2
7844 TURNER 30 1500.0 3
7654 MARTIN 30 1250.0 4
7521 WARD 30 1250.0 5
7900 JAMES 30 950.0 6
----按照部门分组对薪资高低排名 只取薪资高的前俩名
select empno,ename,deptno,sal,rn from (select empno,ename,deptno,sal,row_number() over (partition by deptno order by sal desc) as rn from emp) tmp where rn <3;
empno ename deptno sal
7839 KING 10 5000.0
7782 CLARK 10 2450.0
7788 SCOTT 20 3000.0
7902 FORD 20 3000.0
7698 BLAKE 30 2850.0
7499 ALLEN 30 1600.0
LEAD向后和LAG向前 (列、偏移量、默认值)
id name lag(name,1,0)
1 jack 0
2 tom 0
十、hive的数据导入方式
1、load方式,本地
load data local inpath 'local_path' into table tb_name;
从本地复制了文件到表的路径下
应用场景:大部分的使用,文件几乎都是默认现在本地的
2、load方式,HDFS
load data inpath 'hdfs_path' into table tb_name;
将文件移动到了表的路径下
应用场景:更适合大数据量的存储
3、load方式,overwrite
load data inpath 'hdfs_path' overwrite into table tb_name;
应用场景:适合一些重复写入的表(临时表),作为一个过渡使用
4、子查询方式,as
应用场景:对于数据查询结果的保存
create table stu_as as select name from student;
5、insert方式
传统关系型数据库中,insert是插入一个值
在hive中insert into table后面还是跟一个语句(select语句)
insert into table select sql;
举例:
create table emp_insert like emp;
insert into table emp_insert select * from emp;
应用场景:和子查询类似
6、location
指定一个文件夹,然后将数据导入进去
create table emp1(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int
)
row format delimited fields terminated by '\t'
LOCATION '/user/hive/warehouse/db_emp.db/emp';
load data local inpath '/opt/datas/emp.txt' into table emp;
十一、hive数据的导出
1、insert方式
格式:insert overwrite [local] directory 'path' select sql;
数据导出到本地
insert overwrite local directory '/opt/datas/emp_in01' select * from emp;
-》输出的目标可以提前存在,底层实现的时候,先删除再重新创建
-》指定分隔符
insert overwrite local directory '/opt/datas/emp_in01' row format delimited fields terminated by '\t' select * from emp;
-》HDFS
insert overwrite directory '/emp_insert' select * from emp;
-》注意:上一级的父目录必须存在
2、HDFS SHELL命令 -get
bin/hdfs dfs -get hdfs_path local_path
3、在Linux的命令行使用hive的-e -f参数,将输出重定向保存到本地文件
4、sqoop方式
5、hive支持export和import
-》export
export table tb_name to 'hdfs_path'
-》import
import table tb_name from 'hdfs_path'
十二、hive的常用HQL语句
1、过滤条件
where limit distinct between and null is not null
select * from emp where sal > 3000;
select * from emp limit 1;
select distinct deptno from emp;
select * from emp where sal between 2000 and 3000;
select ename from emp where comm is null;
select ename from emp where comm is not null;
2、聚合函数
count sum avg max min group by having
select count(1) from emp;
select count(*) from emp; -》运行效率较低
select avg(sal) avg_sal from emp;
select deptno,avg(sal) from emp group by deptno;
select deptno,avg(sal) avg_sal from emp group by deptno having avg_sal > 2000;
3、join
等值join
左join left
右join right
全join full
A表:
ID NAME
1 张三
2 李四
3 王五
5 赵六
B表:
ID phone
1 1111
2 2222
3 3333
4 4444
select e.empno,e.ename,d.deptno,e.sal from emp e join dept d on e.deptno=d.deptno;
select e.empno,e.ename,d.deptno,e.sal from emp e left join dept d on e.deptno=d.deptno;
select e.empno,e.ename,d.deptno,e.sal from emp e right join dept d on e.deptno=d.deptno;
select e.empno,e.ename,d.deptno,e.sal from emp e full join dept d on e.deptno=d.deptno;
十三、hive与MR的常用参数设置
设置每个reduce处理的数据量
set hive.exec.reducers.bytes.per.reducer=<number>
<property>
<name>hive.exec.reducers.bytes.per.reducer</name>
<value>1000000000</value>
<description>size per reducer.The default is 1G, i.e if the input size is 10G, it will use 10 reducers.</description>
</property>
设置最大能够运行的reduce个数
set hive.exec.reducers.max=<number>
<property>
<name>hive.exec.reducers.max</name>
<value>999</value>
<description>max number of reducers will be used. If the one
specified in the configuration parameter mapred.reduce.tasks is
negative, Hive will use this one as the max number of reducers when
automatically determine number of reducers.</description>
</property>
实际reduce的个数
set mapreduce.job.reduces=<number>
<property>
<name>mapreduce.job.reduces</name>
<value>1</value>
<description>The default number of reduce tasks per job. Typically set to 99%
of the cluster's reduce capacity, so that if a node fails the reduces can
still be executed in a single wave.
Ignored when mapreduce.jobtracker.address is "local".
</description>
</property>
十四、hive中的几种排序方式
1、order by 全局排序 针对 一个reduce 有效果
select * from emp order by sal;
2、sort by 多个reduce 使用
insert overwrite local directory '/opt/datas/emp_sort' row format delimited fields terminated by '\t' select * from emp sort by sal;
3、distribute by 类似map reduce 的分区
insert overwrite local directory '/opt/datas/emp_dist' row format delimited fields terminated by '\t' select * from emp distribute by deptno sort by sal;
4、cluster by 作用在相同字段上
distribute by+sort by
insert overwrite local directory '/opt/datas/emp_cls' row format delimited fields terminated by '\t' select * from emp cluster by sal;
十五、UDF函数
1、【需求】实现大小写转换
2、在pom.xml文件中添加hive的相关依赖,重新update工程即可
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>0.13.1</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>0.13.1</version>
</dependency>
3、将自己的hive-site.xml文件放到eclipse工程下,便于读取配置
4、继承UDF类,import org.apache.hadoop.hive.ql.exec.UDF;
5、写完程序,打jar包上传到Linux系统中
6、与jar包进行关联
add jar /opt/datas/udf.jar;
7、创建function函数方法
create temporary function my_udf as 'com.bigdata.mapreduce.BigDataUdf';
show functions;---查看有哪些函数。
8、执行将emp表中的ename全部转换成小写
select ename,my_udf(ename) low_ename from emp;
public class BigDataUdf extends UDF{
public Text evaluate(Text str){
return this.evaluate(str, new IntWritable(0));
}
public Text evaluate(Text str,IntWritable flag){
if(str !=null){
if(flag.get()==0){
return new Text(str.toString().toLowerCase());
}else if(flag.get()==1){
return new Text(str.toString().toUpperCase());
}else{
return null;
}
}else{
return null;
}
}
public static void main(String[] args) {
System.out.println(new BigDataUdf().evaluate(new Text("HadoopJava")));
}
}
十六、UDAF用户自定义聚合函数(多进一出)
UDAF是自定义聚合函数,类似于sum()、avg(),这一类函数输入是多个值,输出是一个值。
UDAF是需要hive sql语句和group by联合使用的;hive的group by对于每个分组,只能返回一条记录,这点和mysql不一样,切记。
聚合函数常常需要对大量数组进行操作,所以在编写程序时,一定要注意内存溢出问题。
UDAF分为两种:简单UDAF和通用UDAF。简单UDAF写起来比较简单,但是因为使用了JAVA的反射机制导致性能有所损失,另外有些特性不能使用,如可变参数列表,通用UDAF可以使用所有功能,但是写起来比较复杂。
简单UDAF实例:
package com.autohome.ics.bigdata.common.number;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import java.util.regex.Pattern;
/***对传入的字符串列表,按照数字大小进行排序后,找出最大的值 */
public class MaxIntWithString extends UDAF {
public static class MaxIntWithStringUDAFEvaluator implements UDAFEvaluator{
//最终结果最大的值
private IntWritable MaxResult;
@Override
public void init() { MaxResult=null; }
//每次对一个新值进行聚集计算都会调用iterate方法
//这里将String转换为int后,进行比较大小
public boolean iterate(Text value) {
if(value==null) return false;
if(!isInteger(value.toString())) { return false; }
int number=Integer.parseInt(value.toString());
if(MaxResult==null)
MaxResult=new IntWritable(number);
else
MaxResult.set(Math.max(MaxResult.get(), number));
return true;
}
//Hive需要部分聚集结果的时候会调用该方法
//会返回一个封装了聚集计算当前状态的对象
public IntWritable terminatePartial() {
return MaxResult;
}
//合并两个部分聚集值会调用这个方法
public boolean merge(Text other) {
return iterate(other);
}
//Hive需要最终聚集结果时候会调用该方法
public IntWritable terminate() {
return MaxResult;
}
private static boolean isInteger(String str) {
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
return pattern.matcher(str).matches();
}
}
}
UDAF要继承于UDAF父类org.apache.hadoop.hive.ql.exec.UDAF。1、 内部类要实现org.apache.hadoop.hive.ql.exec.UDAFEvaluator接口。
2、MaxIntWithStringUDAFEvaluator类里需要实现 init、iterate、terminatePartial、merge、terminate这几个函数,是必不可少的
3、 init()方法用来进行全局初始化的。
4、 iterate()中实现比较逻辑。
5、 terminatePartial是Hive部分聚集时调用的,类似于MapReduce里的Combiner,这里能保证能得到各个部分的最大值。
6、 merge是多个部分合并时调用的,得到了参与合并的最大值。
7、terminate是最终Reduce合并时调用的,得到最大值。
UDF UDAF UDTF 知识点链接点击打开链接
hiveserver2
1、作用:将hive变成一种server服务端对外开放,多个客户端可以连接
2、启动server:$ bin/hiveserver2
3、hiveserver2的默认端口号:10000
4、$ bin/beeline
!connect jdbc:hive2://bigdata-01.yushu.com:10000
bin/beeline -u jdbc:hive2://bigdata-01.yushu.com:10000 -n root -p 123456
-》u代表链接的意思
$ bin/beeline --help
-》通过帮助命令获取常用选项参数
二、hive运行配置
<property>
<name>hive.fetch.task.conversion</name>
<value>minimal</value>
<description>
Some select queries can be converted to single FETCH task minimizing latency.
Currently the query should be single sourced not having any subquery and should not have
any aggregations or distincts (which incurs RS), lateral views and joins.
1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
2. more : SELECT, FILTER, LIMIT only (TABLESAMPLE, virtual columns)
----------该模式下不走map reduce 走的是FetchTask任务 它不会启动mapreduce,而是直接读取文件,输出结果
</description>
</property>
虚拟列
One is 【INPUT__FILE__NAME】, which is the input file's name for a mapper task.
the other is 【BLOCK__OFFSET__INSIDE__FILE】, which is the current global file position.
【INPUT__FILE__NAME】代表这行数据属于哪个文件中的
select deptno,dname,INPUT__FILE__NAME from dept;
【BLOCK__OFFSET__INSIDE__FILE】块的偏移量
select deptno,dname,BLOCK__OFFSET__INSIDE__FILE from dept;
Hive远程客户端连接Java代码:
package com.bigdata.mapreduce;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestHiveClient {
private static String driverName="org.apache.hive.jdbc.HiveDriver";
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}
Connection con=DriverManager.getConnection("jdbc:hive2://bigdata-01.yushu.com:10000/db_emp",
"root", "123456");
Statement stmt=con.createStatement();
String sql="select ename,deptno from emp";
System.out.println("Running:"+sql);
ResultSet res=stmt.executeQuery(sql);
while(res.next()){
System.out.println(res.getString(1)+"--------->"+res.getString(2));
}
}
}
【问题】字段中如果包含了分隔符该如何处理?
-》字段加载不全的情况出现,因为hive指定分隔符的实现,每读到一个分隔符就将前面的部分信息作为一个字段
-》使用正则表达式的方式去进行匹配
-》使用正则匹配
CREATE TABLE apachelog (
host STRING,
identity STRING,
user STRING,
time STRING,
request STRING,
status STRING,
size STRING,
referer STRING,
agent STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "([^]*) ([^]*) ([^]*) (-|\\[^\\]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\".*\") ([^ \"]*|\".*\"))?"
)
STORED AS TEXTFILE;
正则表达式:
\代表转义
*代表匹配多个
.*代表匹配所有的
[0-9]代表单个数字
[0-9]*代表0-9之间的多个字符
[^ ]代表非空字符
正则表达式工具网站:
http://wpjam.qiniudn.com/tool/regexpal/
(注)使用Python预处理数据的实现
CREATE TABLE u_data (
userid INT,
movieid INT,
rating INT,
unixtime STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;
wget命令:
从指定的URL地址去下载文件(比较稳定,对于网络环境要求不是很高)
-》在Linux上下载数据包
$ wget http://files.grouplens.org/datasets/movielens/ml-100k.zip
-》使用unzip解压数据包
$ unzip ml-100k.zip
-》加载数据到u_data表中
LOAD DATA LOCAL INPATH '/opt/datas/ml-100k/u.data'
OVERWRITE INTO TABLE u_data;
-》查看下里面的数据
SELECT COUNT(*) FROM u_data;或者count(1)
-》注意:Python的语句格式,代码一定要缩进
-》首先导包
-》语法有点类似Linux shell
-》.strip()移除左右空格,默认就是空格
-》.split('\t')通过这个方法来对于字符串进行切片
-》.isoweekday()通过这个方法最终返回一个比如:如果是周一,那么返回1,以此类推,这样的类型
import sys
import datetime
for line in sys.stdin:
line = line.strip()
userid, movieid, rating, unixtime = line.split('\t')
weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()
print '\t'.join([userid, movieid, rating, str(weekday)])
-》新建结果集表:
CREATE TABLE u_data_new (
userid INT,
movieid INT,
rating INT,
weekday INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t';
-》将weekday_mapper.py脚本文件与hive进行关联,add FILE和add jar功能类似,都是将文件或者jar包添加到hive中
-》add FILE /opt/datas/weekday_mapper.py;
-》注意:一定要写全路径
【插入语句】
INSERT OVERWRITE TABLE u_data_new
SELECT
TRANSFORM (userid, movieid, rating, unixtime)
USING 'python weekday_mapper.py'
AS (userid, movieid, rating, weekday)
FROM u_data;
-》表示标准输出
TRANSFORM (userid, movieid, rating, unixtime)
-》将字段(userid, movieid, rating, unixtime)传递给USING 'python weekday_mapper.py'
-》按照每周进行分组,按照weekday进行分组
SELECT weekday, COUNT(*)
FROM u_data_new
GROUP BY weekday;
-》结果
1 12254
2 13579
3 14430
4 15114
5 14743
6 18229
7 11651
hive时间函数
1、时间格式大体分为两类:
-》标准日期格式:2015-08-31 00:04:37
-》Unixtimestamp:以格林威治时间为基准,或者:Unix时间戳
-》以1970年1月1日0点0分0秒开始一直到现在此时此刻总的秒数
-》是一个long型的数据,秒数
2、hive自带提供了Unixtimestamp的函数方法
-》功能:将日期转换成对应的Unixtimestamp时间戳
-》举例
2015-08-31 00:04:37
2015-09-02 00:00:00
-》先将日期格式转换成Unix时间戳,然后再相减得到最后的时间差
-》使用的业务场景:
-》网站后台处理数据:其中有一个指标【停留时间】
-》【停留时间】是一个衡量网站质量好坏的重要的基准指标之一
-》测试hive自带的函数
select unix_timestamp("2017-05-20 12:00:00") from u_data limit 1;
-》这样的格式无法运行转换出结果,是NULL
select unix_timestamp("20170520 12:00:00") from u_data limit 1;
-》指定格式转化
select unix_timestamp("20170520 12:00:00","yyyyMMdd HH:mm:ss") from u_data limit 1;
-》使用字段进行转换
select unix_timestamp("time","yyyyMMdd HH:mm:ss") from u_data limit 1;
-》from_unixtime将Unix时间戳转换为标准的日期格式,比如:2017-05-20 12:00:00
select from_unixtime(1495252800,"yyyyMMdd HH:mm:ss") from u_data limit 1;
或者
select from_unixtime(1495252800,"yyyy-MM-dd HH:mm:ss") from u_data limit 1;
Hive:case when函数
1、when用来直接判断这一列的值
2、需求:奖金comm这列如果是NULL的话就显示为0
select empno,ename,
case
when comm is null then 0
else comm
end
from emp;
-》结果
empno ename _c2
7369 SMITH 0.0
7499 ALLEN 300.0
7521 WARD 500.0
7566 JONES 0.0
7654 MARTIN 1400.0
7698 BLAKE 0.0
7782 CLARK 0.0
7788 SCOTT 0.0
7839 KING 0.0
7844 TURNER 0.0
7876 ADAMS 0.0
7900 JAMES 0.0
7902 FORD 0.0
7934 MILLER 0.0
select empno,ename,
case
when sal<1000 then 'aaa'
when sal>=1500 and sal<3000 then 'cccc'
else 'ddd'
end as new_sal
from emp;
-》结果
empno ename new_sal
7369 SMITH aaa
7499 ALLEN cccc
7521 WARD ddd
7566 JONES cccc
7654 MARTIN ddd
7698 BLAKE cccc
7782 CLARK cccc
7788 SCOTT ddd
7839 KING ddd
7844 TURNER cccc
7876 ADAMS ddd
7900 JAMES aaa
7902 FORD ddd
7934 MILLER ddd
hive:Cast函数
作用:数据类型的转换
【测试转换】
create table casttest as select empno e_no,ename e_name,cast(sal as string) new_sal from emp;