Hadoop之Hive

本文详细介绍了Hive作为Hadoop上的数据仓库工具的功能和特点,包括Hive的架构、安装部署、基本操作、优化方法等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据。同时,这个语言也允许熟悉 MapReduce 开发者的开发自定义的 mapper 和 reducer 来处理内建的 mapper 和 reducer 无法完成的复杂的分析工作。 
Hive 没有专门的数据格式。 Hive 可以很好的工作在 Thrift 之上,控制分隔符,也允许用户指定数据格式。
Hive 构建在基于静态批处理的Hadoop 之上,Hadoop 通常都有较高的延迟并且在作业提交和调度的时候需要大量的开销。因此,Hive 并不能够在大规模数据集上实现低延迟快速的查询,例如,Hive 在几百MB 的数据集上执行查询一般有分钟级的时间延迟。因此,
Hive 并不适合那些需要低延迟的应用,例如,联机事务处理(OLTP)。Hive 查询操作过程严格遵守Hadoop MapReduce 的作业执行模型,Hive 将用户的HiveQL 语句通过解释器转换为MapReduce 作业提交到Hadoop 集群上,Hadoop 监控作业执行过程,然后返回作业执行结果给用户。Hive 并非为联机事务处理而设计,Hive 并不提供实时的查询和基于行级的数据更新操作。Hive 的最佳使用场合是大数据集的批处理作业,例如,网络日志分析。
Hive 是一种底层封装了Hadoop 的数据仓库处理工具,使用类SQL 的HiveQL 语言实现数据查询,所有Hive 的数据都存储在Hadoop 兼容的文件系统(例如,Amazon S3、HDFS)中。Hive 在加载数据过程中不会对数据进行任何的修改,只是将数据移动到HDFS 中Hive 设定的目录下,因此,Hive 不支持对数据的改写和添加,所有的数据都是在加载的时候确定的。Hive 的设计特点如下。
● 支持索引,加快数据查询。
● 不同的存储类型,例如,纯文本文件、HBase 中的文件。
● 将元数据保存在关系数据库中,大大减少了在查询过程中执行语义检查的时间。
● 可以直接使用存储在Hadoop 文件系统中的数据。
● 内置大量用户函数UDF 来操作时间、字符串和其他的数据挖掘工具,支持用户扩展UDF 函数来完成内置函数无法实现的操作。
● 类SQL 的查询方式,将SQL 查询转换为MapReduce 的job 在Hadoop集群上执行。
Hive 体系结构

主要分为以下几个部分:
用户接口
用户接口主要有三个:CLI,Client 和 WUI。其中最常用的是 CLI,Cli 启动的时候,会同时启动一个 Hive 副本。Client 是 Hive 的客户端,用户连接至 Hive Server。在启动 Client 模式的时候,需要指出 Hive Server 所在节点,并且在该节点启动 Hive Server。 WUI 是通过浏览器访问 Hive。
元数据存储
Hive 将元数据存储在数据库中,如 mysql、derby。Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等。
解释器、编译器、优化器、执行器
解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在 HDFS 中,并在随后由 MapReduce 调用执行。
Hadoop
Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成(包含 * 的查询,比如 select * from tbl 不会生成 MapReduce 任务)。

数据存储

首先,Hive 没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由的组织 Hive 中的表,只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,Hive 就可以解析数据。
其次,Hive 中所有的数据都存储在 HDFS 中,Hive 中包含以下数据模型:表(Table),外部表(External Table),分区(Partition),桶(Bucket)。
Hive 中的 Table 和数据库中的 Table 在概念上是类似的,每一个 Table 在 Hive 中都有一个相应的目录存储数据。例如,一个表 pvs,它在 HDFS 中的路径为:/wh/pvs,其中,wh 是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的数据仓库的目录,所有的 Table 数据(不包括 External Table)都保存在这个目录中。
Partition 对应于数据库中的 Partition 列的密集索引,但是 Hive 中 Partition 的组织方式和数据库中的很不相同。在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中。例如:pvs 表中包含 ds 和 city 两个 Partition,则对应于 ds = 20090801, ctry = US 的 HDFS 子目录为:/wh/pvs/ds=20090801/ctry=US;对应于 ds = 20090801, ctry = CA 的 HDFS 子目录为;/wh/pvs/ds=20090801/ctry=CA
Buckets 对指定列计算 hash,根据 hash 值切分数据,目的是为了并行,每一个 Bucket 对应一个文件。将 user 列分散至 32 个 bucket,首先对 user 列的值计算 hash,对应 hash 值为 0 的 HDFS 目录为:/wh/pvs/ds=20090801/ctry=US/part-00000;hash 值为 20 的 HDFS 目录为:/wh/pvs/ds=20090801/ctry=US/part-00020
External Table 指向已经在 HDFS 中存在的数据,可以创建 Partition。它和 Table 在元数据的组织上是相同的,而实际数据的存储则有较大的差异。
Table 的创建过程和数据加载过程(这两个过程可以在同一个语句中完成),在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。
  • External Table 只有一个过程,加载数据和创建表同时完成(CREATE EXTERNAL TABLE ……LOCATION),实际数据是存储在 LOCATION 后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个 External Table 时,仅删除元数据,表中的数据不会真正被删除。

基本语法

基本数据类型

hive支持多种不同长度的整型和浮点型数据,支持布尔型,也支持无长度限制的字符串类型。例如:TINYINT、SMALINT、BOOLEAN、FLOAT、DOUBLE、STRING等基本数据类型。这些基本数据类型和其他sql方言一样,都是保留字。

集合数据类型

hive中的列支持使用struct、map和array集合数据类型。大多数关系型数据库中不支持这些集合数据类型,因为它们会破坏标准格式。关系型数据库中为实现集合数据类型是由多个表之间建立合适的外键关联来实现。在大数据系统中,使用集合类型的数据的好处在于提高数据的吞吐量,减少寻址次数来提高查询速度。
使用集合数据类型创建表实例:
CREATE TABLE STUDENTINFO
(
NAME STRING,
FAVORITE ARRAY<STRING>,
COURSE MAP<STRING,FLOAT>,
ADDRESS STRUCT<CITY:STRING,STREET:STRING>
)
查询语法:SELECT S.NAME,S.FAVORITE[0],S.COURSE["ENGLISH"],S.ADDRESS.CITY FROM STUDENTINFO S;

分区表

创建分区表:create table employee (name string,age int,sex string) partitioned by (city string) row format delimited fields terminated by '\t';
分区表装载数据:load data local inpath '/usr/local/lee/employee' into table employee partition (city='hubei');

Hive常用优化方法

1、join连接时的优化:当三个或多个以上的表进行join操作时,如果每个on使用相同的字段连接时只会产生一个mapreduce。
2、join连接时的优化:当多个表进行查询时,从左到右表的大小顺序应该是从小到大。原因:hive在对每行记录操作时会把其他表先缓存起来,直到扫描最后的表进行计算
3、在where字句中增加分区过滤器。
4、当可以使用left semi join 语法时不要使用inner join,前者效率更高。原因:对于左表中指定的一条记录,一旦在右表中找到立即停止扫描。
5、如果所有表中有一张表足够小,则可置于内存中,这样在和其他表进行连接的时候就能完成匹配,省略掉reduce过程。设置属性即可实现,set hive.auto.covert.join=true; 用户可以配置希望被优化的小表的大小 set hive.mapjoin.smalltable.size=2500000; 如果需要使用这两个配置可置入$HOME/.hiverc文件中。
6、同一种数据的多种处理:从一个数据源产生的多个数据聚合,无需每次聚合都需要重新扫描一次。
例如:insert overwrite table student select * from employee; insert overwrite table person select * from employee;
可以优化成:from employee insert overwrite table student select * insert overwrite table person select *
7、limit调优:limit语句通常是执行整个语句后返回部分结果。set hive.limit.optimize.enable=true;
8、开启并发执行。某个job任务中可能包含众多的阶段,其中某些阶段没有依赖关系可以并发执行,开启并发执行后job任务可以更快的完成。设置属性:set hive.exec.parallel=true;
9、hive提供的严格模式,禁止3种情况下的查询模式。
a:当表为分区表时,where字句后没有分区字段和限制时,不允许执行。
b:当使用order by语句时,必须使用limit字段,因为order by 只会产生一个reduce任务。
c:限制笛卡尔积的查询。
10、合理的设置map和reduce数量。
11、jvm重用。可在hadoop的mapred-site.xml中设置jvm被重用的次数。


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;



基于hadoopHive数据仓库JavaAPI简单调用的实例,关于Hive的简介在此不赘述。hive提供了三种用户接口:CLI,JDBC/ODBC和 WebUI CLI,即Shell命令行 JDBC/ODBC 是 Hive 的Java,与使用传统数据库JDBC的方式类似 WebGUI是通过浏览器访问 Hive 本文主要介绍的就是第二种用户接口,直接进入正题。 1、Hive 安装: 1)hive的安装请参考网上的相关文章,测试时只在hadoop一个节点上安装hive即可。 2)测试数据data文件'\t'分隔: 1 zhangsan 2 lisi 3 wangwu 3)将测试数据data上传到linux目录下,我放置在:/home/hadoop01/data 2、在使用 JDBC 开发 Hive 程序时, 必须首先开启 Hive 的远程服务接口。使用下面命令进行开启: Java代码 收藏代码 hive --service hiveserver >/dev/null 2>/dev/null & 我们可以通过CLI、Client、Web UI等Hive提供的用户接口来和Hive通信,但这三种方式最常用的是CLI;Client 是Hive的客户端,用户连接至 Hive Server。在启动 Client 模式的时候,需要指出Hive Server所在节点,并且在该节点启动 Hive Server。 WUI 是通过浏览器访问 Hive。今天我们来谈谈怎么通过HiveServer来操作Hive。   Hive提供了jdbc驱动,使得我们可以用Java代码来连接Hive并进行一些类关系型数据库的sql语句查询等操作。同关系型数据库一样,我们也需要将Hive的服务打开;在Hive 0.11.0版本之前,只有HiveServer服务可用,你得在程序操作Hive之前,必须在Hive安装的服务器上打开HiveServer服务,如下: 1 [wyp@localhost/home/q/hive-0.11.0]$ bin/hive --service hiveserver -p10002 2 Starting Hive Thrift Server 上面代表你已经成功的在端口为10002(默认的端口是10000)启动了hiveserver服务。这时候,你就可以通过Java代码来连接hiveserver,代码如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值