大数据技术之Hive
01 hive入门
1.1 什么是Hive
1)Hive简介
Hive是由Facebook开源,基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
那为什么会有Hive呢?它是为了解决什么问题而诞生的呢?
下面通过一个案例,来快速了解一下Hive。
例如:需求,统计单词出现个数。
(1)在Hadoop中我们用MapReduce程序实现的,当时需要写Mapper、Reducer和Driver三个类,并实现对应逻辑,相对繁琐。
(2)如果通过Hive SQL实现,一行就搞定了,简单方便,容易理解。
2)Hive本质
Hive是一个Hadoop客户端,用于将HQL(Hive SQL)转化成MapReduce程序。
(1)Hive中每张表的数据存储在HDFS
(2)Hive分析数据底层的实现是MapReduce(也可配置为Spark或者Tez)
(3)执行程序运行在Yarn上
1.2 Hive架构原理
1)用户接口:Client
CLI(command-line interface)、JDBC/ODBC。
说明:JDBC和ODBC的区别。
(1)JDBC的移植性比ODBC好;(通常情况下,安装完ODBC驱动程序之后,还需要经过确定的配置才能够应用。而不相同的配置在不相同数据库服务器之间不能够通用。所以,安装一次就需要再配置一次。JDBC只需要选取适当的JDBC数据库驱动程序,就不需要额外的配置。在安装过程中,JDBC数据库驱动程序会自己完成有关的配置。)
(2)两者使用的语言不同,JDBC在Java编程时使用,ODBC一般在C/C++编程时使用。
2)元数据:Metastore
元数据包括:数据库(默认是default)、表名、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。
默认存储在自带的derby数据库中,由于derby数据库只支持单客户端访问,生产环境中为了多人开发,推荐使用MySQL存储Metastore。
3)驱动器:Driver
(1)解析器(SQLParser):将SQL字符串转换成抽象语法树(AST)
(2)语义分析(Semantic Analyzer):将AST进一步划分为QeuryBlock
(3)逻辑计划生成器(Logical Plan Gen):将语法树生成逻辑计划
(4)逻辑优化器(Logical Optimizer):对逻辑计划进行优化
(5)物理计划生成器(Physical Plan Gen):根据优化后的逻辑计划生成物理计划
(6)物理优化器(Physical Optimizer):对物理计划进行优化
(7)执行器(Execution):执行该计划,得到查询结果并返回给客户
4)Hadoop
使用HDFS进行存储,可以选择MapReduce/Tez/Spark进行计算。
02 Hive安装
2.1 Hive安装地址
1)Hive官网地址
http://hive.apache.org/
2)文档查看地址
https://cwiki.apache.org/confluence/display/Hive/GettingStarted
3)下载地址
http://archive.apache.org/dist/hive/
4)github地址
https://github.com/apache/hive
2.2 Hive安装部署
2.2.1 安装Hive
1)把apache-hive-3.1.3-bin.tar.gz上传到Linux的/opt/software目录下
2)解压apache-hive-3.1.3-bin.tar.gz到/opt/module/目录下面
3)修改apache-hive-3.1.3-bin.tar.gz的名称为hive
4)修改/etc/profile.d/my_env.sh,添加环境变量
(1)添加内容
(2)source一下
5)初始化元数据库(默认是derby数据库)
2.2.2 启动并使用Hive
1)启动Hive
2)使用Hive
观察HDFS的路径/user/hive/warehouse/stu,体会Hive与Hadoop之间的关系。
Hive中的表在Hadoop中是目录;Hive中的数据在Hadoop中是文件。
3)在Xshell窗口中开启另一个窗口开启Hive,在/tmp/zy目录下监控hive.log文件
原因在于Hive默认使用的元数据库为derby。derby数据库的特点是同一时间只允许一个客户端访问。如果多个Hive客户端同时访问,就会报错。由于在企业开发中,都是多人协作开发,需要多客户端同时访问Hive,怎么解决呢?我们可以将Hive的元数据改为用MySQL存储,MySQL支持多客户端同时访问。
4)首先退出hive客户端。然后在Hive的安装目录下将derby.log和metastore_db删除,顺便将HDFS上目录删除
5)删除HDFS中/user/hive/warehouse/stu中数据
2.3 MySQL安装
2.3.1 安装MySQL
1)上传MySQL安装包以及MySQL驱动jar包
2)解压MySQL安装包
3)卸载系统自带的mariadb
4)安装MySQL依赖
5)安装mysql-client
6)安装mysql-server
7)启动MySQL
8)查看MySQL密码
2.3.2 配置MySQL
配置主要是root用户 + 密码,在任何主机上都能登录MySQL数据库。
1)用刚刚查到的密码进入MySQL(如果报错,给密码加单引号)
2)设置复杂密码(由于MySQL密码策略,此密码必须足够复杂)
3)更改MySQL密码策略
4)设置简单好记的密码
5)进入MySQL库
6)查询user表
7)修改user表,把Host表内容修改为%
8)刷新
9)退出
2.3.3 卸载MySQL说明
若因为安装失败或者其他原因,MySQL需要卸载重装,可参考以下内容。
(1)清空原有数据
①通过/etc/my.cnf查看MySQL数据的存储位置
②去往/var/lib/mysql路径需要root权限
(2)卸载MySQL相关包
①查看安装过的MySQL相关包
②一键卸载命令
2.4 配置Hive元数据存储到MySQL
2.4.1 配置元数据到MySQL
1)新建Hive元数据库
2)将MySQL的JDBC驱动拷贝到Hive的lib目录下。
3)在$HIVE_HOME/conf目录下新建hive-site.xml文件
5)初始化Hive元数据库(修改为采用MySQL存储元数据)
2.4.2 验证元数据是否配置成功
1)再次启动Hive
2)使用Hive
3)在Xshell窗口中开启另一个窗口开启Hive(两个窗口都可以操作Hive,没有出现异常)
2.4.3 查看MySQL中的元数据
1)登录MySQL
2)查看元数据库metastore
(1)查看元数据库中存储的库信息
(2)查看元数据库中存储的表信息
(3)查看元数据库中存储的表中列相关信息
2.5 Hive服务部署
2.5.1 hiveserver2服务
Hive的hiveserver2服务的作用是提供jdbc/odbc接口,为用户提供远程访问Hive数据的功能,例如用户期望在个人电脑中访问远程服务中的Hive数据,就需要用到Hiveserver2。
1)用户说明
在远程访问Hive数据时,客户端并未直接访问Hadoop集群,而是由Hivesever2代理访问。由于Hadoop集群中的数据具备访问权限控制,所以此时需考虑一个问题:那就是访问Hadoop集群的用户身份是谁?是Hiveserver2的启动用户?还是客户端的登录用户?
答案是都有可能,具体是谁,由Hiveserver2的hive.server2.enable.doAs参数决定,该参数的含义是是否启用Hiveserver2用户模拟的功能。若启用,则Hiveserver2会模拟成客户端的登录用户去访问Hadoop集群的数据,不启用,则Hivesever2会直接使用启动用户访问Hadoop集群数据。模拟用户的功能,默认是开启的。
具体逻辑如下:
未开启用户模拟功能:
开启用户模拟功能:
生产环境,推荐开启用户模拟功能,因为开启后才能保证各用户之间的权限隔离。
2)hiveserver2部署
(1)Hadoop端配置
hivesever2的模拟用户功能,依赖于Hadoop提供的proxy user(代理用户功能),只有Hadoop中的代理用户才能模拟其他用户的身份访问Hadoop集群。因此,需要将hiveserver2的启动用户设置为Hadoop的代理用户,配置方式如下:
修改配置文件core-site.xml,然后记得分发三台机器
增加如下配置:
(2)Hive端配置
在hive-site.xml文件中添加如下配置信息
3)测试
(1)启动hiveserver2
(2)使用命令行客户端beeline进行远程访问
启动beeline客户端
(3)使用Datagrip图形化客户端进行远程访问
4)配置DataGrip连接
(1)创建连接
(2)配置连接属性
所有属性配置,和Hive的beeline客户端配置一致即可。初次使用,配置过程会提示缺少JDBC驱动,按照提示下载即可。
(3)界面介绍
(4)测试sql执行
(5)修改数据库
2.5.2 metastore服务
Hive的metastore服务的作用是为Hive CLI或者Hiveserver2提供元数据访问接口。
1)metastore运行模式
metastore有两种运行模式,分别为嵌入式模式和独立服务模式。下面分别对两种模式进行说明:
(1)嵌入式模式
(2)独立服务模式
生产环境中,不推荐使用嵌入式模式。因为其存在以下两个问题:
(1)嵌入式模式下,每个Hive CLI都需要直接连接元数据库,当Hive CLI较多时,数据库压力会比较大。
(2)每个客户端都需要用户元数据库的读写权限,元数据库的安全得不到很好的保证。
2)metastore部署
(1)嵌入式模式
嵌入式模式下,只需保证Hiveserver2和每个Hive CLI的配置文件hive-site.xml中包含连接元数据库所需要的以下参数即可:
(2)独立服务模式
独立服务模式需做以下配置:
首先,保证metastore服务的配置文件hive-site.xml中包含连接元数据库所需的以下参数:
其次,保证Hiveserver2和每个Hive CLI的配置文件hive-site.xml中包含访问metastore服务所需的以下参数:
注意:主机名需要改为metastore服务所在节点,端口号无需修改,metastore服务的默认端口就是9083。
3)测试
此时启动Hive CLI,执行shou databases语句,会出现一下错误提示信息:
这是因为我们在Hive CLI的配置文件中配置了hive.metastore.uris参数,此时Hive CLI会去请求我们执行的metastore服务地址,所以必须启动metastore服务才能正常使用。
metastore服务的启动命令如下:
注意:启动后该窗口不能再操作,需打开一个新的Xshell窗口来对Hive操作。
重新启动 Hive CLI,并执行shou databases语句,就能正常访问了
2.6 Hive使用技巧
2.6.1 Hive常用交互命令
1)在Hive命令行里创建一个表student,并插入1条数据
2)“-e”不进入hive的交互窗口执行hql语句
3)“-f”执行脚本中的hql语句
(1)在/opt/module/hive/下创建datas目录并在datas目录下创建hivef.sql文件
(2)文件中写入正确的hql语句
(3)执行文件中的hql语句
(4)执行文件中的hql语句并将结果写入文件中
2.6.2 Hive参数配置方式
1)查看当前所有的配置信息
2)参数的配置三种方式
(1)配置文件方式
默认配置文件:hive-default.xml
用户自定义配置文件:hive-site.xml
注意:用户自定义配置会覆盖默认配置。另外,Hive也会读入Hadoop的配置,因为Hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置。配置文件的设定对本机启动的所有Hive进程都有效。
(2)命令行参数方式
①启动Hive时,可以在命令行添加-hiveconf param=value来设定参数。例如:
注意:仅对本次Hive启动有效。
②查看参数设置
(3)参数声明方式
可以在HQL中使用SET关键字设定参数,例如:
注意:仅对本次Hive启动有效。
查看参数设置:
上述三种设定方式的优先级依次递增。即配置文件 < 命令行参数 < 参数声明。注意某些系统级的参数,例如log4j相关的设定,必须用前两种方式设定,因为那些参数的读取在会话建立以前已经完成了。
2.6.3 Hive常见属性配置
1)Hive客户端显示当前库和表头
(1)在hive-site.xml中加入如下两个配置:
(2)hive客户端在运行时可以显示当前使用的库和表头信息
2)Hive运行日志路径配置
(1)Hive的log默认存放在/tmp/zy/hive.log目录下(当前用户名下)
(2)修改Hive的log存放日志到/opt/module/hive/logs
修改$HIVE_HOME/conf/hive-log4j2.properties.template文件名称为
hive-log4j2.properties
在hive-log4j2.properties文件中修改log存放位置
修改配置如下
3)Hive的JVM堆内存设置
新版本的Hive启动的时候,默认申请的JVM堆内存大小为256M,JVM堆内存申请的太小,导致后期开启本地模式,执行复杂的SQL时经常会报错:java.lang.OutOfMemoryError: Java heap space,因此最好提前调整一下HADOOP_HEAPSIZE这个参数。
(1)修改$HIVE_HOME/conf下的hive-env.sh.template为hive-env.sh
(2)将hive-env.sh其中的参数 export HADOOP_HEAPSIZE修改为2048,重启Hive。
修改前
修改后
4)关闭Hadoop虚拟内存检查
在yarn-site.xml中关闭虚拟内存检查(虚拟内存校验,如果已经关闭了,就不需要配了)。
(1)修改前记得先停Hadoop
(2)添加如下配置
(3)修改完后记得分发yarn-site.xml,并重启yarn。
03 DDL(Data Definition Language)数据定义
3.1 数据库(database)
3.1.1 创建数据库
1)语法
2)案例
(1)创建一个数据库,不指定路径
注:若不指定路径,其默认路径为
(2)创建一个数据库,指定路径
(3)创建一个数据库,带有dbproperties
3.1.2 查询数据库
1)展示所有数据库
(1)语法
注:like通配表达式说明:*表示任意个任意字符,|表示或的关系。
(2)案例
2)查看数据库信息
(1)语法
(2)案例
①查看基本信息
②查看更多信息
3.1.3 修改数据库
用户可以使用alter database命令修改数据库某些信息,其中能够修改的信息包括dbproperties、location、owner user。需要注意的是:修改数据库location,不会改变当前已有表的路径信息,而只是改变后续创建的新表的默认的父目录。
1)语法
2)案例
(1)修改dbproperties
3.1.4 删除数据库
1)语法
注:RESTRICT:严格模式,若数据库不为空,则会删除失败,默认为该模式。
CASCADE:级联模式,若数据库不为空,则会将库中的表一并删除。
2)案例
(1)删除空数据库
(2)删除非空数据库
3.1.5 切换当前数据库
1)语法
3.2 表(table)
3.2.1 创建表
3.2.1.1 语法
1)普通建表
(1)完整语法
(2)关键字说明:
①TEMPORARY
临时表,该表只在当前会话可见,会话结束,表会被删除。
②EXTERNAL(重点)
外部表,与之相对应的是内部表(管理表)。管理表意味着Hive会完全接管该表,包括元数据和HDFS中的数据。而外部表则意味着Hive只接管元数据,而不完全接管HDFS中的数据。
③data_type(重点)
Hive中的字段类型可分为基本数据类型和复杂数据类型。
基本数据类型如下:
复杂数据类型如下;
注:类型转换
Hive的基本数据类型可以做类型转换,转换的方式包括隐式转换以及显示转换。
方式一:隐式转换
具体规则如下:
a. 任何整数类型都可以隐式地转换为一个范围更广的类型,如tinyint可以转换成int,int可以转换成bigint。
b. 所有整数类型、float和string类型都可以隐式地转换成double。
c. tinyint、smallint、int都可以转换为float。
d. boolean类型不可以转换为任何其它的类型。
详情可参考Hive官方说明:https://cwiki.apache.org/confluence/display/hive/languagemanual+types
Allowed Implicit Conversions
方式二:显示转换
可以借助cast函数完成显示的类型转换
a.语法
b.案例
④PARTITIONED BY(重点)
创建分区表
⑤CLUSTERED BY ... SORTED BY...INTO ... BUCKETS(重点)
创建分桶表
⑥ROW FORMAT(重点)
指定SERDE,SERDE是Serializer and Deserializer的简写。Hive使用SERDE序列化和反序列化每行数据。详情可参考 Hive-Serde。语法说明如下:
语法一:DELIMITED关键字表示对文件中的每个字段按照特定分割符进行分割,其会使用默认的SERDE对每行数据进行序列化和反序列化。
注:
fields terminated by :列分隔符
collection items terminated by : map、struct和array中每个元素之间的分隔符
map keys terminated by :map中的key与value的分隔符
lines terminated by :行分隔符
语法二:SERDE关键字可用于指定其他内置的SERDE或者用户自定义的SERDE。例如JSON SERDE,可用于处理JSON字符串。
⑦STORED AS(重点)
指定文件格式,常用的文件格式有,textfile(默认值),sequence file,orc file、parquet file等等。
⑧LOCATION
指定表所对应的HDFS路径,若不指定路径,其默认值为
⑨TBLPROPERTIES
用于配置表的一些KV键值对参数
2)Create Table As Select(CTAS)建表
该语法允许用户利用select查询语句返回的结果,直接建表,表的结构和查询语句的结构保持一致,且保证包含select查询语句放回的内容。
3)Create Table Like语法
该语法允许用户复刻一张已经存在的表结构,与上述的CTAS语法不同,该语法创建出来的表中不包含数据。
3.2.1.2 案例
1)内部表与外部表
(1)内部表
Hive中默认创建的表都是的内部表,有时也被称为管理表。对于内部表,Hive会完全管理表的元数据和数据文件。
创建内部表如下:
准备其需要的文件如下,注意字段之间的分隔符。
上传文件到Hive表指定的路径
删除表,观察数据HDFS中的数据文件是否还在
(2)外部表
外部表通常可用于处理其他工具上传的数据文件,对于外部表,Hive只负责管理元数据,不负责管理HDFS中的数据文件。
创建外部表如下:
上传文件到Hive表指定的路径
删除表,观察数据HDFS中的数据文件是否还在
2)SERDE和复杂数据类型
本案例重点练习SERDE和复杂数据类型的使用。
若现有如下格式的JSON文件需要由Hive进行分析处理,请考虑如何设计表?
注:以下内容为格式化之后的结果,文件中每行数据为一个完整的JSON字符串。
我们可以考虑使用专门负责JSON文件的JSON Serde,设计表字段时,表的字段与JSON字符串中的一级字段保持一致,对于具有嵌套结构的JSON字符串,考虑使用合适复杂数据类型保存其内容。最终设计出的表结构如下:
创建该表,并准备以下文件。注意,需要确保文件中每行数据都是一个完整的JSON字符串,JSON SERDE才能正确的处理。
上传文件到Hive表指定的路径
尝试从复杂数据类型的字段中取值
3)create table as select和create table like
(1)create table as select
(2)create table like
3.2.2 查看表
1)展示所有表
(1)语法
注:like通配表达式说明:*表示任意个任意字符,|表示或的关系。
(2)案例
2)查看表信息
(1)语法
注:EXTENDED:展示详细信息
FORMATTED:对详细信息进行格式化的展示
(2)案例
①查看基本信息
②查看更多信息
3.2.3 修改表
1)重命名表
(1)语法
(2)案例
2)修改列信息
(1)语法
①增加列
该语句允许用户增加新的列,新增列的位置位于末尾。
②更新列
该语句允许用户修改指定列的列名、数据类型、注释信息以及在表中的位置。
③替换列
该语句允许用户用新的列集替换表中原有的全部列。
2)案例
(1)查询表结构
(2)添加列
(3)查询表结构
(4)更新列
(5)替换列
3.2.4 删除表
1)语法
2)案例
3.2.5 清空表
1)语法
注意:truncate只能清空管理表,不能删除外部表中数据。
2)案例
04 DML(Data Manipulation Language)数据操作
4.1 Load
Load语句可将文件导入到Hive表中。
1)语法
关键字说明:
(1)local:表示从本地加载数据到Hive表;否则从HDFS加载数据到Hive表。
(2)overwrite:表示覆盖表中已有数据,否则表示追加。
(3)partition:表示上传到指定分区,若目标是分区表,需指定分区。
2)实操案例
(0)创建一张表
(1)加载本地文件到hive
(2)加载HDFS文件到hive中
①上传文件到HDFS
②加载HDFS上数据,导入完成后去HDFS上查看文件是否还存在
(3)加载数据覆盖表中已有的数据
①上传文件到HDFS
②加载数据覆盖表中已有的数据
4.2 Insert
4.2.1 将查询结果插入表中
1)语法
关键字说明:
(1)INTO:将结果追加到目标表
(2)OVERWRITE:用结果覆盖原有数据
2)案例
(1)新建一张表
(2)根据查询结果插入数据
4.2.2 将给定Values插入表中
1)语法
2)案例
4.2.3 将查询结果写入目标路径
1)语法
2)案例
4.3 Export&Import
Export导出语句可将表的数据和元数据信息一并到处的HDFS路径,Import可将Export导出的内容导入Hive,表的数据和元数据信息都会恢复。Export和Import可用于两个Hive实例之间的数据迁移。
1)语法
2)案例
05 查询
5.1 基础语法
1)官网地址
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select
2)查询语句语法:
5.2 基本查询(Select…From)
5.2.1 数据准备
(0)原始数据
①在/opt/module/hive/datas/路径上创建dept.txt文件,并赋值如下内容:
部门编号 部门名称 部门位置id
②在/opt/module/hive/datas/路径上创建emp.txt文件,并赋值如下内容:
员工编号 姓名 岗位 薪资 部门
(1)创建部门表
(2)创建员工表
(3)导入数据
5.2.2 全表和特定列查询
1)全表查询
2)选择特定列查询
注意:
(1)SQL 语言大小写不敏感。
(2)SQL 可以写在一行或者多行。
(3)关键字不能被缩写也不能分行。
(4)各子句一般要分行写。
(5)使用缩进提高语句的可读性。
5.2.3 列别名
1)重命名一个列
2)便于计算
3)紧跟列名,也可以在列名和别名之间加入关键字‘AS’
4)案例实操
查询名称和部门。
5.2.4 Limit语句
典型的查询会返回多行数据。limit子句用于限制返回的行数。
5.2.5 Where语句
1)使用where子句,将不满足条件的行过滤掉
2)where子句紧随from子句
3)案例实操
查询出薪水大于1000的所有员工。
注意:where子句中不能使用字段别名。
5.2.6 关系运算函数
1)基本语法
如下操作符主要用于where和having语句中。
5.2.7 逻辑运算函数
1)基本语法(and/or/not)
2)案例实操
(1)查询薪水大于1000,部门是30
(2)查询薪水大于1000,或者部门是30
(3)查询除了20部门和30部门以外的员工信息
5.2.8 聚合函数
1)语法
count(*),表示统计所有行数,包含null值;
count(某列),表示该列一共有多少行,不包含null值;
max(),求最大值,不包含null,除非所有值都是null;
min(),求最小值,不包含null,除非所有值都是null;
sum(),求和,不包含null。
avg(),求平均值,不包含null。
2)案例实操
(1)求总行数(count)
hive sql执行过程:
(2)求工资的最大值(max)
hive sql执行过程:
(3)求工资的最小值(min)
hive sql执行过程:
(4)求工资的总和(sum)
hive sql执行过程:
(5)求工资的平均值(avg)
hive sql执行过程:
5.3 分组
5.3.1 Group By语句
Group By语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。
1)案例实操:
(1)计算emp表每个部门的平均工资。
hive sql执行过程:
(2)计算emp每个部门中每个岗位的最高薪水。
hive sql执行过程:
5.3.2 Having语句
1)having与where不同点
(1)where后面不能写分组聚合函数,而having后面可以使用分组聚合函数。
(2)having只用于group by分组统计语句。
2)案例实操
(1)求每个部门的平均薪水大于2000的部门
①求每个部门的平均工资。
hive sql执行过程:
②求每个部门的平均薪水大于2000的部门。
hive sql执行过程:
5.4 Join语句
5.4.1 等值Join
Hive支持通常的sql join语句,但是只支持等值连接,不支持非等值连接。
1)案例实操
(1)根据员工表和部门表中的部门编号相等,查询员工编号、员工名称和部门名称。
hive sql执行过程:
5.4.2 表的别名
1)好处
(1)使用别名可以简化查询。
(2)区分字段的来源。
2)案例实操
合并员工表和部门表。
5.4.3 内连接
内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
5.4.4 左外连接
左外连接:join操作符左边表中符合where子句的所有记录将会被返回。
5.4.5 右外连接
右外连接:join操作符右边表中符合where子句的所有记录将会被返回。
5.4.6 满外连接
满外连接:将会返回所有表中符合where语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用null值替代。
5.4.7 多表连接
注意:连接n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
数据准备,在/opt/module/hive/datas/下:vim location.txt
部门位置id 部门位置
1)创建位置表
2)导入数据
3)多表连接查询
大多数情况下,Hive会对每对join连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表e和表d进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表l进行连接操作。
注意:为什么不是表d和表l先进行连接操作呢?这是因为Hive总是按照从左到右的顺序执行的。
5.4.8 笛卡尔集
1)笛卡尔集会在下面条件下产生
(1)省略连接条件
(2)连接条件无效
(3)所有表中的所有行互相连接
2)案例实操
hive sql执行过程:
5.4.9 联合(union & union all)
1)union&union all上下拼接
union和union all都是上下拼接sql的结果,这点是和join有区别的,join是左右关联,union和union all是上下拼接。union去重,union all不去重。
union和union all在上下拼接sql结果时有两个要求:
(1)两个sql的结果,列的个数必须相同
(2)两个sql的结果,上下所对应列的类型必须一致
2)案例实操
将员工表30部门的员工信息和40部门的员工信息,利用union进行拼接显示。
5.5 排序
5.5.1 全局排序(Order By)
Order By:全局排序,只有一个Reduce。
1)使用Order By子句排序
asc(ascend):升序(默认)
desc(descend):降序
2)Order By子句在select语句的结尾
3)基础案例实操
(1)查询员工信息按工资升序排列
hive sql执行过程:
(2)查询员工信息按工资降序排列
4)按照别名排序案例实操
按照员工薪水的2倍排序。
hive sql执行过程:
5)多个列排序案例实操
按照部门和工资升序排序。
hive sql执行过程:
5.5.2 每个Reduce内部排序(Sort By)
Sort By:对于大规模的数据集order by的效率非常低。在很多情况下,并不需要全局排序,此时可以使用Sort by。
Sort by为每个reduce产生一个排序文件。每个Reduce内部进行排序,对全局结果集来说不是排序。
1)设置reduce个数
2)查看设置reduce个数
3)根据部门编号降序查看员工信息
hive sql执行过程:
4)将查询结果导入到文件中(按照部门编号降序排序)
5.5.3 分区(Distribute By)
Distribute By:在有些情况下,我们需要控制某个特定行应该到哪个Reducer,通常是为了进行后续的聚集操作。distribute by子句可以做这件事。distribute by类似MapReduce中partition(自定义分区),进行分区,结合sort by使用。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
1)案例实操:
(1)先按照部门编号分区,再按照员工编号薪资排序
注意:
distribute by的分区规则是根据分区字段的hash码与reduce的个数进行相除后,余数相同的分到一个区。
Hive要求distribute by语句要写在sort by语句之前。
演示完以后mapreduce.job.reduces的值要设置回-1,否则下面分区or分桶表load跑MapReduce的时候会报错。
hive sql执行过程:
5.5.4 分区排序(Cluster By)
当distribute by和sort by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是升序排序,不能指定排序规则为asc或者desc。
(1)以下两种写法等价
注意:按照部门编号分区,不一定就是固定死的数值,可以是20号和30号部门分到一个分区里面去。
hive sql执行过程:
06 函数
6.1 函数简介
Hive会将常用的逻辑封装成函数给用户进行使用,类似于Java中的函数。
好处:避免用户反复写逻辑,可以直接拿来使用。
重点:用户需要知道函数叫什么,能做什么。
Hive提供了大量的内置函数,按照其特点可大致分为如下几类:单行函数、聚合函数、炸裂函数、窗口函数。
以下命令可用于查询所有内置函数的相关信息。
1)查看系统内置函数
2)查看内置函数用法
3)查看内置函数详细信息
6.2 单行函数
单行函数的特点是一进一出,即输入一行,输出一行。
单行函数按照功能可分为如下几类: 日期函数、字符串函数、集合函数、数学函数、流程控制函数等。
6.2.1 算术运算函数
案例实操:查询出所有员工的薪水后加1显示。
6.2.2 数值函数
1)round:四舍五入
2)ceil:向上取整
3)floor:向下取整
6.2.3 字符串函数
1)substring:截取字符串
语法一:substring(string A, int start)
返回值:string
说明:返回字符串A从start位置到结尾的字符串
语法二:substring(string A, int start, int len)
返回值:string
说明:返回字符串A从start位置开始,长度为len的字符串
案例实操:
(1)获取第二个字符以后的所有字符
(2)获取倒数第三个字符以后的所有字符
(3)从第3个字符开始,向后获取2个字符
2)replace :替换
语法:replace(string A, string B, string C)
返回值:string
说明:将字符串A中的子字符串B替换为C。
3)regexp_replace:正则替换
语法:regexp_replace(string A, string B, string C)
返回值:string
说明:将字符串A中的符合java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符。
案例实操:
4)regexp:正则匹配
语法:字符串 regexp 正则表达式
返回值:boolean
说明:若字符串符合正则表达式,则返回true,否则返回false。
(1)正则匹配成功,输出true
(2)正则匹配失败,输出false
5)repeat:重复字符串
语法:repeat(string A, int n)
返回值:string
说明:将字符串A重复n遍。
6)split :字符串切割
语法:split(string str, string pat)
返回值:array
说明:按照正则表达式pat匹配到的内容分割str,分割后的字符串,以数组的形式返回。
7)nvl :替换null值
语法:nvl(A,B)
说明:若A的值不为null,则返回A,否则返回B。
8)concat :拼接字符串
语法:concat(string A, string B, string C, ……)
返回:string
说明:将A,B,C……等字符拼接为一个字符串
9)concat_ws:以指定分隔符拼接字符串或者字符串数组
语法:concat_ws(string A, string…| array(string))
返回值:string
说明:使用分隔符A拼接多个字符串,或者一个数组的所有元素。
10)get_json_object:解析json字符串
语法:get_json_object(string json_string, string path)
返回值:string
说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。
案例实操:
(1)获取json数组里面的json具体数据
(2)获取json数组里面的数据
6.2.4 日期函数
1)unix_timestamp:返回当前或指定时间的时间戳
语法:unix_timestamp()
返回值:bigint
案例实操:
说明:-前面是日期后面是指,日期传进来的具体格式
2)from_unixtime:转化UNIX时间戳(从 1970-01-01 00:00:00 UTC 到指定时间的秒数)到当前时区的时间格式
语法:from_unixtime(bigint unixtime[, string format])
返回值:string
案例实操:
3)current_date:当前日期
4)current_timestamp:当前的日期加时间,并且精确的毫秒
5)month:获取日期中的月
语法:month (string date)
返回值:int
案例实操:
6)day:获取日期中的日
语法:day (string date)
返回值:int
案例实操:
7)hour:获取日期中的小时
语法:hour (string date)
返回值:int
案例实操:
8)datediff:两个日期相差的天数(结束日期减去开始日期的天数)
语法:datediff(string enddate, string startdate)
返回值:int
案例实操:
9)date_add:日期加天数
语法:date_add(string startdate, int days)
返回值:string
说明:返回开始日期 startdate 增加 days 天后的日期
案例实操:
10)date_sub:日期减天数
语法:date_sub (string startdate, int days)
返回值:string
说明:返回开始日期startdate减少days天后的日期。
案例实操:
11)date_format:将标准日期解析成指定格式字符串
6.2.5 流程控制函数
1)case when:条件判断函数
语法一:case when a then b [when c then d]* [else e] end
返回值:T
说明:如果a为true,则返回b;如果c为true,则返回d;否则返回 e
语法二: case a when b then c [when d then e]* [else f] end
返回值: T
说明:如果a等于b,那么返回c;如果a等于d,那么返回e;否则返回f
2)if: 条件判断,类似于Java中三元运算符
语法:if(boolean testCondition, T valueTrue, T valueFalseOrNull)
返回值:T
说明:当条件testCondition为true时,返回valueTrue;否则返回valueFalseOrNull
(1)条件满足,输出正确
输出:正确
(2)条件满足,输出错误
输出:错误
6.2.6 集合函数
1)size:集合中元素的个数
2)map:创建map集合
语法:map (key1, value1, key2, value2, …)
说明:根据输入的key和value对构建map类型
案例实操:
3)map_keys: 返回map中的key
4)map_values: 返回map中的value
5)array 声明array集合
语法:array(val1, val2, …)
说明:根据输入的参数构建数组array类
案例实操:
6)array_contains: 判断array中是否包含某个元素
7)sort_array:将array中的元素排序
8)struct声明struct中的各属性
语法:struct(val1, val2, val3, …)
说明:根据输入的参数构建结构体struct类
案例实操:
9)named_struct声明struct的属性和值
6.2.7 案例演示
1. 数据准备
1)表结构
2)建表语句
3)插入数据
2. 需求
1)统计每个月的入职人数
(1)期望结果
(2)需求实现
2)查询每个人的年龄(年 + 月)
(1)期望结果
(2)需求实现
3)按照薪资,奖金的和进行倒序排序,如果奖金为null,置位0
(1)期望结果
(2)需求实现
4)查询每个人有多少个朋友
(1)期望结果
(2)需求实现
5)查询每个人的孩子的姓名
(1)期望结果
(2)需求实现
6)查询每个岗位男女各多少人
(1)期望结果
(2)需求实现
6.3 高级聚合函数
多进一出 (多行传入,一个行输出)。
1)普通聚合 count/sum....
2)collect_list 收集并形成list集合,结果不去重
结果:
女["行政","研发","行政","前台"]
男["销售","研发","销售","前台"]
3)collect_set 收集并形成set集合,结果去重
结果:
女["行政","研发","前台"]
男["销售","研发","前台"]
6.3.1 案例演示
1)每个月的入职人数以及姓名
结果:
month cn name_list
4 2 ["宋青书","周芷若"]
6 1 ["黄蓉"]
7 1 ["郭靖"]
8 2 ["张无忌","杨过"]
9 2 ["赵敏","小龙女"]
6.4 炸裂函数
6.4.1 概述
6.4.2 案例演示
1.数据准备
1)表结构
2)建表语句
3)装载语句
2. 需求
1)需求说明
根据上述电影信息表,统计各分类的电影数量,期望结果如下:
2)答案
6.5 窗口函数(开窗函数)
6.5.1 概述
6.5.2 常用窗口函数
按照功能,常用窗口可划分为如下几类:聚合函数、跨行取值函数、排名函数。
1)聚合函数
max:最大值。
min:最小值。
sum:求和。
avg:平均值。
count:计数。
2)跨行取值函数
(1)lead和lag
注:lag和lead函数不支持自定义窗口。
(2)first_value和last_value
3)排名函数
注:rank 、dense_rank、row_number不支持自定义窗口。
6.5.3 案例演示
1.数据准备
1)表结构
2)建表语句
3)装载语句
2. 需求
1)统计每个用户截至每次下单的累积下单总额
(1)期望结果
(2)需求实现
2)统计每个用户截至每次下单的当月累积下单总额
(1)期望结果
(2)需求实现
3)统计每个用户每次下单距离上次下单相隔的天数(首次下单按0天算)
(1)期望结果
(2)需求实现
4)查询所有下单记录以及每个用户的每个下单记录所在月份的首/末次下单日期
(1)期望结果
(2)需求实现
5)为每个用户的所有下单记录按照订单金额进行排名
(1)期望结果
(2)需求实现
6.6 自定义函数
1)Hive自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。
2)当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
3)根据用户自定义函数类别分为以下三种:
(1)UDF(User-Defined-Function)
一进一出。
(2)UDAF(User-Defined Aggregation Function)
用户自定义聚合函数,多进一出。
类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions)
用户自定义表生成函数,一进多出。
如lateral view explode()
4)官方文档地址
https://cwiki.apache.org/confluence/display/Hive/HivePlugins
5)编程步骤
(1)继承Hive提供的类
org.apache.hadoop.hive.ql.udf.generic.GenericUDF
org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
(2)实现类中的抽象方法
(3)在hive的命令行窗口创建函数添加jar。
创建function。
(4)在hive的命令行窗口删除函数
6.7 自定义UDF函数
0)需求
自定义一个UDF实现计算给定基本数据类型的长度,例如:
1)创建一个Maven工程Hive
2)导入依赖
3)创建一个类
4)创建临时函数
(1)打成jar包上传到服务器/opt/module/hive/datas/myudf.jar
(2)将jar包添加到hive的classpath,临时生效
(3)创建临时函数与开发好的java class关联
(4)即可在hql中使用自定义的临时函数
(5)删除临时函数
注意:临时函数只跟会话有关系,跟库没有关系。只要创建临时函数的会话不断,在当前会话下,任意一个库都可以使用,其他会话全都不能使用。
5)创建永久函数
(1)创建永久函数
注意:因为add jar本身也是临时生效,所以在创建永久函数的时候,需要制定路径(并且因为元数据的原因,这个路径还得是HDFS上的路径)。
(2)即可在hql中使用自定义的永久函数
(3)删除永久函数
注意:永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。
永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。
永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上,库名.函数名。
07 分区表和分桶表
7.1 分区表
Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区,这样的查询效率会提高很多。
7.1.1 分区表基本语法
1. 创建分区表
2. 分区表读写数据
1)写数据
(1)load
①数据准备
在/opt/module/hive/datas/路径上创建文件dept_20220401.log,并输入如下内容。
②装载语句
(2)insert
将day='20220401'分区的数据插入到day='20220402'分区,可执行如下装载语句
2)读数据
查询分区表数据时,可以将分区字段看作表的伪列,可像使用其他字段一样使用分区字段。
3. 分区表基本操作
1)查看所有分区信息
2)增加分区
(1)创建单个分区
(2)同时创建多个分区(分区之间不能有逗号)
3)删除分区
(1)删除单个分区
(2)同时删除多个分区(分区之间必须有逗号)
4)修复分区
Hive将分区表的所有分区信息都保存在了元数据中,只有元数据与HDFS上的分区路径一致时,分区表才能正常读写数据。若用户手动创建/删除分区路径,Hive都是感知不到的,这样就会导致Hive的元数据和HDFS的分区路径不一致。再比如,若分区表为外部表,用户执行drop partition命令后,分区元数据会被删除,而HDFS的分区路径不会被删除,同样会导致Hive的元数据和HDFS的分区路径不一致。
若出现元数据和HDFS路径不一致的情况,可通过如下几种手段进行修复。
(1)add partition
若手动创建HDFS的分区路径,Hive无法识别,可通过add partition命令增加分区元数据信息,从而使元数据和分区路径保持一致。
(2)drop partition
若手动删除HDFS的分区路径,Hive无法识别,可通过drop partition命令删除分区元数据信息,从而使元数据和分区路径保持一致。
(3)msck
若分区元数据和HDFS的分区路径不一致,还可使用msck命令进行修复,以下是该命令的用法说明。
说明:
msck repair table table_name add partitions:该命令会增加HDFS路径存在但元数据缺失的分区信息。
msck repair table table_name drop partitions:该命令会删除HDFS路径已经删除但元数据仍然存在的分区信息。
msck repair table table_name sync partitions:该命令会同步HDFS路径和元数据分区信息,相当于同时执行上述的两个命令。
msck repair table table_name:等价于msck repair table table_name add partitions命令。
7.1.2 二级分区表
思考:如果一天内的日志数据量也很大,如何再将数据拆分?答案是二级分区表,例如可以在按天分区的基础上,再对每天的数据按小时进行分区。
1)二级分区表建表语句
2)数据装载语句
3)查询分区数据
7.1.3 动态分区
动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。
1)动态分区相关参数
(1)动态分区功能总开关(默认true,开启)
(2)严格模式和非严格模式
动态分区的模式,默认strict(严格模式),要求必须指定至少一个分区为静态分区,nonstrict(非严格模式)允许所有的分区字段都使用动态分区。
(3)一条insert语句可同时创建的最大的分区个数,默认为1000。
(4)单个Mapper或者Reducer可同时创建的最大的分区个数,默认为100。
(5)一条insert语句可以创建的最大的文件个数,默认100000。
(6)当查询结果为空时且进行动态分区时,是否抛出异常,默认false。
2)案例实操
需求:将dept表中的数据按照地区(loc字段),插入到目标表dept_partition_dynamic的相应分区中。
(1)创建目标分区表
(2)设置动态分区
(3)查看目标分区表的分区情况
7.2 分桶表
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分,分区针对的是数据的存储路径,分桶针对的是数据文件。
分桶表的基本原理是,首先为每行数据计算一个指定字段的数据的hash值,然后模以一个指定的分桶数,最后将取模运算结果相同的行,写入同一个文件中,这个文件就称为一个分桶(bucket)。
7.2.1 分桶表基本语法
1)建表语句
2)数据装载
(1)数据准备
在/opt/module/hive/datas/路径上创建student.txt文件,并输入如下内容。
(2)导入数据到分桶表中
说明:Hive新版本load数据可以直接跑MapReduce,老版的Hive需要将数据传到一张表里,再通过查询的方式导入到分桶表里面。
(3)查看创建的分桶表中是否分成4个桶
(4)观察每个分桶中的数据
7.2.2 分桶排序表
1)建表语句
2)数据装载
(1)导入数据到分桶表中
(2)查看创建的分桶表中是否分成4个桶
(3)观察每个分桶中的数据
未完待续
新
年
快
乐
“
2023 NEW YEAR
漫话架构之美
大数据领域原创技术号,专注于大数据研究,包括 Hadoop、Flink、Spark、Kafka、Hive、HBase 等,深入大数据技术原理,数据仓库,数据治理,前沿大数据技术