Hive
数据仓库(Data Warehouse,简称数仓、DW),是一个用于存储,分许,报告的数据系统。
数据仓库的目的是构建面向分析的集成数据环境,分析结果为企业提供决策支持。
数据仓库本身并不是“生产”任何数据,其数据来源于不同外部系统;
同时数据仓库自身也不需要‘消费“任何的数据,其结果开放给各个外部应用使用;
这也是为什么叫“仓库”,而不叫“工厂”的原因
联机事物处理 OLTP
联机分析处理OLAP
OLTP系统
- 操作型处理,叫联机事物处理OLTP,主要目标是做数据处理,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改
- 用户较为关心操作的响应时间,数据的安全性,完整性和并发支持的用户数等问题。
- 传统的关系型数据库系统,作为数据管理的主要手段,主要用于操作型处理。
OLTP系统
- 分析型处理,叫联机分析处理OLAP,主要目标是做数据分析。
- 一般针对某些主题的历史数据进行复杂的多维分析,支持管理决策。
- 数据仓库是OLAP系统的一个典型实例,主要用于数据分析。
对比
OLTP OLAP 数据源 仅包含当前运行日常业务 整合来自多个来源的数据,包括OLTP和外部来源 目的 面向应用,面向业务,支撑事务 面向主题,面向分析,支撑分析决策 焦点 当下 主要面向过去,面向历史,实时数仓除外 任务 读写操作 大量读而很少写操作 响应时间 毫秒 秒,分钟,小时,或者天取决于数据和查询复杂性 数据量 小数据,MB,GB 大数据,TP,PB 数据仓库、数据库的区别
- 数据仓库不是大型的数据库,虽然数据仓库存储数据规模大。
- 数据仓库的出现,并不是要取代数据库
- 数据库是面向事务的设计,数据仓库是面向主题的设计的。
- 数据库一般存储业务数据,数据仓库存储的一般是历史数据
- 数据库是为了捕获数据而设计,数据仓库是为了分析数据而设计
数据仓库,数据集市
- 数据仓库是面向整个集团组织的数据,数据集市是面向单个部门使用的。
- 可以任务数据集市是数据仓库的子集,也有人吧数据集市叫做小型数据仓库。数据集市通常只涉及一个主题领域,例如市场营销或者销售。因为他们较小且更具体,所以他们通常更易于管理和维护,并具有更灵活的结构。
数据仓库分层架构的好处
分层的主要原因是在管理数据的时候,能对数据有一个更加清晰的掌控,详细来讲,主要有下面几个原因:
- 清晰数据结构
每一个数据分层都有它的作用域,在使用表的时候能更方便的定位和理解。
- 数据血缘最终
简单来说,我们最终给业务呈现的是一个能直接使用业务表,但是它的来源有很多,如果有一张来源表出问题了,我们希望能够快速准确地定位到问题,并清楚它的危害范围。
- 减少重复开发
规范数据分层,开发一些通用的中间层数据,能够减少极大的重复计算。
- 把复杂问题简单化
将一个复杂的任务分解成多个步骤来完成,每一层只处理单一的步骤,比较简单的容易理解,而且便于维护数据的准确性,当数据出现问题之后,可以不用修复所有的数据,只需要从有问题的步骤开始修复。
- 屏蔽原始数据的异常
屏蔽业务的影响,不必该一次业务就需要重新接入数据
- Apache Hive是一款建立在Hadoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化,半结构化数据文件映射为一张数据库表,基于表提供了一种类似SQL的查询模块,称为Hive查询语言(HQL),用于访问和分析存储在Hadoop文件中的大型数据集。
- Hive核心是将HQL转换为MapReduce存续,然后将程序提交到Hadoop集群执行。
- Hive由Facebook实现并开源。
使用Hadoop MapReduce直接处理数据所面临的问题
- 人员学习成本太高需要掌握java语言
- MapReduce实现复杂查询逻辑开发难度太大
使用Hive处理数据的好处
- 操作接口采用类SQL语法,提供快速开发的能力(简单,容易上手)
- 避免直接写MapReduce,减少开发人员的学习成本
- 支持自定义函数,功能扩展很方便
- 背靠Hadoop,擅长存储分析的海量数据集
从功能来说,数据仓库软件,至少需要具备下述两种能力:
- 存储数据的能力,分析数据的能力
Apache Hive作为一款大数据时代的数据仓库软件,当然也具备上述两种能力。只不过Hive并不是自己实现了上述两种能力,而是借助Hadoop.
- Hive利用HDFS存储数据,利用MapReduce查询分析数据
这样突然发现Hive没啥用,不过是套壳Hadoop罢了。其实不然,Hive的最大的魅力在于用户专注于编写HQL,Hive帮您转换为MapReduce程序对数据的分析。
Hive能将数据文件映射成一张表,这个映射是指什么?
- 文件和表之间的对应关系
Hive软件本身到底承担了什么功能职责?
- SQL语法解析编译成为MapReduce
组件
- 用户接口
包括CLI、JDBC/ODBC、WebCUI。其中,CLI为shell命令行;Hive中的Thrift服务器语序外部客户端通过网络与Hive进行交互,类似于JDBC或ODBC协议。WebCUI是通过浏览器访问Hive.
Data Model概念
- 数据模型:用来描述数据,组织数据和对数据进行操作,是对现实世界数据特征的描述。
- Hive的数据模型类似于RDBMS库表结构,此外还有自己特有的模型。
- Hive中的数据可以在粒度级别上分为三类:
Table 表
Partition 分区
Bucket 桶
Databases 数据库
Hive作为一个数据仓库,在结构上积极向传统数据库看齐,也分数据仓库(Schema),每个数据库下面有各自的表组成。默认数据库default.
Hive的数据都是存储在HDFS上的,默认有一个根目录,在Hive-site.xml中,由参数hive.metastore.warehouse.dir指定。默认值为/user/hive/warehouse。
因此,Hive中的数据库在HDFS上的存储路径为:
${hive.metastore.warehouse.dir}/databasename.db
- 比如,名为itcast的数据库存储路径为:
/user/hive/warehouse/itcast.db
Tables 表
Hive表与关系数据库中的表相同。Hive中的表所对应的数据通常是存储在HDFS中,而表相关的元数据是存储在RDBMS中。
Hive中的表的数据在HDFS上的存储路径为:
${hive.metastore.warehouse.dir}/databasename.db/tablename
- 比如,itcast的数据库下t_user表存储路径为:
/user/hive/warehouse/itcast.db/t_user
Partitions分区
- Partition分区是hive的一种优化手段表。分区是指根据分区列(例如“日期day”)的值将表划分为不同分区。这样可以更快的对指定分区数据进行查询。
- 分区在存储层面上的表现是:table表目录下以子文件夹形式存在。
- 一个文件夹表示一个分区。子文件命名标准:分区列=分区值
- Hive还支持分区下继续创建分区,所谓的多重分区。关于分区表的使用和详细介绍,后面模块会单独展开
Buckets 分桶
- Bucket分桶表示hive的一种优化手段。分桶是指根据字段(例如“编号ID”)的值,经过hash计算规则将数据文件划分成指定的若干个小文件。
- 分桶规则:hashfunc(字段)% 桶个数,余数相同的分到同一个文件。
Hive虽然具有RDBNS数据 库的外表,包括数据模型、SQL语法都十分相似,但应用场景却完全不同
Hive只适合用来做海量数据的离线分析。Hive的定位是数据仓库,面向分析的OLAP系统。
因此时刻告诉自己,HIve不是大型数据库,也不是要取代Mysql承担业务数据处理。
什么是元数据
- 元数据,又称中介数据、中继数据,为描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。、
Hive Metadata
- Hive Metadata即Hive的元数据
- 包含用Hive创建的database、table、表的位置、类型等元信息。
- 元数据存储在关系型数据库中。如Hive内置的Derby、或者第三方如MySql等。
Hive Metastore
- Metastore即元数据服务。Metastore服务的作用是管理metadata元数据,对外暴露服务地址,让各种客户端通过连接metastore服务,由metastore在去连接MySQL数据库来存储元数据。
- 有了metastore服务,就可以有多个客户端同时连接,而且这些客户端不需要知道MySQL数据库的用户名和密码,只需要连接metastore服务即可,某种程度上也保证了hive元数据的安全。
内嵌模式
- 内嵌模式是metastore默认部署模式。
- 此种模式下,元数据存储在内置的Derby数据库,并且Derby和metastore都会启动。不需要额外起Metastore服务。
- 但是一次只能支持一个活动用户,适用于测试体验,不适用与生产环境。
本地模式
- 本地模式下,Metastore服务HiveServer进程在同一进程中运行,但是存储元数据的数据库在单独的进程中运行,并且可以在单独的主机上。metastore服务将通过JDBC与metastore数据库进行通信。
- 本地模式采用外部数据库来存储元数据,推荐使用MySQL
- hive根据hive.metastore.uris 参数值来判断,如果为空,则为本地模式。
- 缺点是:每启动一次hive服务,都内置启动了一个metastore。
远程模式
- 远程模式下,Metastore服务在其自己的单独JVM上运行,而不在HiveServer的JVM中运行。如果其他进程希望与Metastore服务器通信,则可以使用ThriftNetwork API进行通信。
- 远程模式下,需要配置hive.metastore.uris参数来指定metastore服务运行的机器ip和端口,并且需要单独手动启动metastore服务。元数据也采用外部数据库来存储元数据,推荐使用MySQL
- 由于Apache Hive是一款基于Hadoop的数据仓库软件,通常部署运行在Linux系统之上。因此不管使用何种方式配置Hive Metastore,必须要先保证服务的基础环境正常,Hadoop集群健康可用。
- 服务其基础环境
- 集群时间同步,防火墙关闭,主机Host映射,免密登录,JDK安装
- Hadoop集群健康可用
- 启动Hive之前必须先启动Hadoop集群,特别要注意,需要等待HDFS安全模式关闭之后在启动运行Hive.
- Hive不是分布式安装运行的软件,其分布式的特性主要借由Hadoop完成,包括分布式存储,分布式计算。
- 因此Hive需要把数据存储在HDFS上,并且通过MapReduce作为执行引擎处理数据;
- 以你需要在hadoop中添加相关配置属性,以满足Hive在Hadoop上运行
- 修改Hadoop中core-site.xml,并且Hadoop集群同步配置文件,重启生效(该配置是配置非root用户之外的用户登陆)。
<property> <name>hadoop.proxyuser.root.hostsname> <value>*value> property> <property> <name>hadoop.proxyuser.root.groupsname> <value>*value> property>
- 内嵌模式特征就是:不需要安装数据库,不需要配置启动Metastore服务,解压安装包初始化即可测试体验Hive.
- 注意:Hive3版本需要用户手动进行元数据初始化动作。
- 内嵌模式下,判断是否初始化成功的依据是执行命令之后输出信息和命令的当前路径下是否有文件生成
内嵌模式安装
#上传解压安装包 tar -zxvf apache-hive-2.1.1-bin.tar.gz -C /usr/local #修改hive安装路径名,方便以后使用 mv apache-hive-2.1.1-bin/ hive #解决hadoop、hive之间guava版本差异(这里想不要操作,如果jar包有问题出现异常在试试) # cd /usr/local/src/hive # rm -rf lib/guava-19.0.jar # cp /usr/local/src/hadoop/share/hadoop/common/lib/guava-11.0.2.jar ./lib/ #修改hive环境变量文件 添加Hadoop_HOME cd /hive/conf/ mv hive-env.sh.template hive-env.sh vim hive -env.sh export HADOOP_HOME=/usr/local/src/hadoop export HIVE_CONF_DIR=/usr/local/src/hive/conf export HIVE_AUX_JARS_PATH=/usr/local/src/hive/lib #初始化metadata cd /usr/local/hive bin/schematool -dbType derby -initSchema #进入环境变量文件 vim /etc/profile #添加如下内容: export HIVE_HOME=/usr/local/src/hive export PATH=$HIVE_HOME/bin:$PATH #让profile生效 source /etc/profile
- 本地模式特征就是:需要安装数据库MySQL来存储元数据,但是不需要配置启动Metastore服务。
- 注意:Hive3版本需要用户手动进行元数据初始化动作。
MySQL模式安装
#卸载Centos7自带mariadb rpm -qa|grep mariadb rpm -qa|grep mysql rpm -e 查询到的包名 --nodeps #创建mysql安装包存放点 mkdir /usr/local/src/mysql #上传mysql-5.7.29安装包到上述文件夹下、解压 tar xvf mysql-5.7.29-1.el7.x86_64.rpm-bundle.tar #执行安装 yum -y install libaio rpm -ivh mysql-community-common-5.7.29-1.el7.x86_64.rpm mysql-community-libs-5.7.29-1.el7.x86_64.rpm mysql-community-client-5.7.29-1.el7.x86_64.rpm mysql-community-server-5.7.29-1.el7.x86_64.rpm #初始化mysql mysqld --initialize #更改所属组 chown mysql:mysql /var/lib/mysql -R #启动mysql systemctl start mysqld.service #查看生成的临时root密码 grep 'temporary password' /var/log/mysqld.log #这行日志的最后就是随机生成的临时密码(这个不是以上命令的,忽略即可) #[Note] A temporary password is generated for root@localhost: o+TU+KDOm004 #修改mysql root密码、授权远程访问 mysql -u root -p Enter password: #这里输入在日志中生成的临时密码 #更改mysql的root用户的登陆密码设置为hadoop mysql> alter user user() identified by "hadoop"; #更改成功显示 Query OK, 0 rows affected (0.00 sec) #授权 mysql> use mysql; mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'hadoop' WITH GRANT OPTION; mysql> FLUSH PRIVILEGES; #或者也可以使用下面指令授权(这里是尚硅谷的,上面是黑马的,这里容易出错,建议使用上面) mysql> use mysql; #使用mysql表 mysql> select User,Host from user; #查询user表 mysql> update user set host='%' where host='localhost'; #把host表的内容修改为% mysql> delete from user where Host='127.0.0.1'; #删除root用户其他的host #mysql的启动和关闭 状态查看 systemctl stop mysqld systemctl status mysqld systemctl start mysqld #建议设置为开机自启动服务 systemctl enable mysqld #查看是否已经设置自启动成功 systemctl list-unit-files | grep mysqld
Hive本地模式安装
#--------------------Hive安装配置---------------------- # 上传解压安装包 cd /usr/local/src/ tar zxvf apache-hive-3.1.2-bin.tar.gz mv apache-hive-3.1.2-bin hive #解决hadoop、hive之间guava版本差异(这里想不要操作,如果jar包有问题出现异常在试试) # cd /usr/local/src/hive # rm -rf lib/guava-19.0.jar # cp /usr/local/src/hadoop/share/hadoop/common/lib/guava-11.0.2.jar ./lib/ #添加mysql jdbc驱动到hive安装包lib/文件下 mysql-connector-java-5.1.32.jar #如果没有这个包,可以在官网进行下载 #修改hive环境变量文件 添加Hadoop_HOME cd /export/server/hive/conf/ mv hive-env.sh.template hive-env.sh vim hive-env.s export HADOOP_HOME=/usr/local/src/hadoop export HIVE_CONF_DIR=/usr/local/src/hive/conf export HIVE_AUX_JARS_PATH=/usr/local/src/hive/lib #新增hive-site.xml 配置mysql等相关信息 vim hive-site.xml #在文件中添加以下配置即可 #-----------------Hive-site.xml--------------------- <configuration> <!-- 存储元数据mysql相关配置 --> <property> <name>javax.jdo.option.ConnectionURL</name> <value> jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>hadoop</value> </property> <!-- 关闭元数据存储授权 --> <property> <name>hive.metastore.event.db.notification.api.auth</name> <value>false</value> </property> <!-- 关闭元数据存储版本的验证 --> <property> <name>hive.metastore.schema.verification</name> <value>false</value> </property> </configuration> #---------------------切换到命令行继续操作-------------------------- #初始化metadata cd /usr/local/src/hive bin/schematool -initSchema -dbType mysql -verbos #登陆mysql查看是否初始化成功,初始化成功会在mysql中创建74张表 mysql> show databases; mysql> use hive; msql> show tables; #启动hive服务 bin/hive #在启动hive服务之前首先要想启动metastore,如果没有启动使用HQL指令查询会报错,启动metastore使用 bin/hive --service metastore #启动hiveserver2服务,如果想在IDEA或beeline客户端进行使用的话则必须启动hiveserver2服务 bin/hive --service hiveserver2 #启动hive前的注意事项,在启动hive时需要启动metastore服务,因为,hive时通过metastore进行对元数据进行交互的,内嵌模式和本地模式启动hive的同时会自动启动metastore服务,远程模式下,需要自己手动启动,在使用beeline客户端和IDEA进行连接的时候,要想启动hiveserver2服务,因为beeline是需要先连接到hiveserver2在有hiveserver2连接到metastore,在有metastore进行交互
- 远程模式最大的特点有两个:
- 需要安装MySQL来存储Hive元数据;
- 需要手动单独配置启动Metastore服务
- 本系列课程中采用远程模式安装Hive。
远程模式安装
# 这里使用的hive版本是 # 安装远程模式之前吧MySQL安装好,上面有步骤 # 上传解压安装包 cd /export/server/ tar zxvf apache-hive-3.1.2-bin.tar.gz mv apache-hive-3.1.2-bin hive #解决hadoop、hive之间guava版本差异(这里不用操作,因为操作容易造成metastore 和hiveserver2启动异常,改了就会jar包冲突) cd /export/server/hive rm -rf lib/guava-19.0.jar cp /usr/local/src/hadoop/share/hadoop/common/lib/guava-27.0-jre.jar ./lib/ #添加mysql jdbc驱动到hive安装包lib/文件下 mysql-connector-java-5.1.32.jar #修改hive环境变量文件 添加Hadoop_HOME cd /usr/local/src/hive/conf mv hive-env.sh.template hive-env.sh vim hive-env.sh export HADOOP_HOME=/usr/local/src/hadoop export HIVE_CONF_DIR=/usr/local/src/hive/conf export HIVE_AUX_JAcd RS_PATH=/usr/local/src/hive/lib #新增hive-site.xml 配置mysql等相关信息 vim hive-site.xml #初始化metadata cd /usr/local/src/hive bin/schematool -initSchema -dbType mysql -verbos #初始化成功会在mysql中创建74张表 #-----------------hive-site.xml-------------- <configuration> <!-- 存储元数据mysql相关配置 --> <property> <name>javax.jdo.option.ConnectionURL</name> <value> jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8</value> </property> <!-- 使用指定的连接驱动进行连接 --> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>hadoop</value> </property> <!-- H2S运行绑定host --> <property> <name>hive.server2.thrift.bind.host</name> <value>master</value> </property> <!-- 远程模式部署metastore 服务地址 --> <property> <name>hive.metastore.uris</name> <value>thrift://master:9083</value> </property> <!-- 关闭元数据存储授权 --> <property> <name>hive.metastore.event.db.notification.api.auth</name> <value>false</value> </property> <!-- 关闭元数据存储版本的验证 --> <property> <name>hive.metastore.schema.verification</name> <value>false</value> </property> </configuration> #-----------------core-site.xml-------------- <property> <name>hadoop.proxyuser.root.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.root.groups</name> <value>*</value> </property> #-----------------Metastore Hiveserver2启动---- #前台启动 关闭ctrl+cha /usr/local/src/hive/bin/hive --service metastore #后台启动 进程挂起 关闭使用jps + kill #输入命令回车执行 再次回车 进程将挂起后台 nohup /export/server/hive/bin/hive --service metastore & #前台启动开启debug日志 /export/server/hive/bin/hive --service metastore --hiveconf hive.root.logger=DEBUG,console
Hive发展至今,总共经历了两代客户端工具。
- 第一代客户端(deprecated 不推荐使用):$HIVE_HOME/bin/hive,是一个shellUtil.主要功能;一是可以用于以交互或批处理模式运行Hive查询;二是用于Hive相关服务的启动,比如metastore服务。
- 第二代客户端(recommended 推荐使用):$HIVE_HOME/bin/beeline,是一个JDBC客户端,是官方强烈推荐使用的Hive行工具,和第一点客户端相比,性能加强安全性提高。
Beeline 客户端
- Beeline在嵌入式模式和远程模式下均可工作。
- 在嵌入模式下,它运行嵌入式Hive(类似Hive Client);而远程模式下beeline通过Thrift连接到单独的HiveServer2服务上,这也是官方推荐在生产环境中使用的模式。
HiveServer、HiveServer2服务
- HiveServer、HiveServer2都是Hive自带的两种服务,允许客户端在不启动CLI(命令行)的情况下对Hive中的数据进行操作,且两个都允许远程客户端使用多种编程语言如Java,python等面向hive提交请求,取回结果。
- 但是,HiveServer不能处理多于一个客户端的并发请求,因此在Hive-0.11.0版本中重写了HiveServer代码得到了HiveServer2,进而解决了该问题。HiveServer已经被废弃。
- HiveServere2支持多客户端的并发和身份认证,只在为开放API客户端如JDBC、ODBC提供更好的支持。
关系梳理
HiveServer2通过Metastore服务读写元数据。所以在远程模式下,启动HiveServer2之前必须首先启动metastore服务。
特别注意:远程模式下,Beeline客户端只能通过HiveServer2服务访问Hive.而bin/hive是通过Metastore服务访问的。
在hive安装包的bin目录下,有hive提供的第一代客户端bin/hive。该客户端可以访问Hive的metastore服务,从而达到操作Hive的目的。
友情提示:如果您是远程模式部署,请手动启动运行metastore服务。如果是内嵌模式和本地模式,直接运行bin/hive,metastore服务会内嵌一起启动。
可以直接在启动Hive metastore 服务的机器上使用bin/hive客户端操作,此时不需要进行任何配置。
#远程模式 首先启动metastore服务 /usr/local/src/hive/bin/hive --service metastore #克隆CRT回话窗口 使用hive client连接 /usr/local/src/hive/bin/hive
hive经过发展,推出了第二代客户端beeli但是beeline客户端不是直接访问metastore服务的,而是需要单独启动hiveserver2服务。
在hive安装的服务器上,首先启动metastore服务,然后启动hiveserver2服务
#先启动metastore服务 然后启动hiveserver2服务 nohup /usr/local/src/hive/bin/hive --service metastore & nohup /usr/local/src/hive/bin/hive --service hiveserver2 &
在node3上使用beeline客户端进行连接访问。需要注意hiveserver2服务启动之后需要稍等一会才可以对外提供服务。
Beeline是JDBC的客户端,通过JDBC协议和Hiveserver2服务进行通信,协议的地址是:jdbc:hive2://node1:10000
! connect jdbc:hive2://master:10000
bin/hive -e "select * from aa;" #hiv后面家参数e,就可以直接在命令行执行hql语句了 bin/hive -f ./hive.hql #在命令行执行一个写好的hql文件 /usr/local/src/hive/bin/hive -f hive.hql >> ./history.txt #在命令行模式下执行一个编写好的hql文件,在吧执行的结果追加到history.txt文件中
#1、在hive cli命令窗口中如何查看hdfs文件系统 hive> dfs -ls /; #2、在hive cli命令窗口中如何查看本地文件系统 hive> !ls /opt/module/datas; #3、查看在hive中输入的所有历史命令 #(1)进入到当前用户的根目录/root或/home/atguigu #(2)查看.hivehistory文件 cat .hivehistory #4、在hive cli命令窗口以键值对的形式查看相应配置的配置 hive> set mapred.reduce.tasks; #5、在命令行使用键值对的方式更改相应配置的信息 bin/hive -hiveconf mapred.reduce.tasks
结论:
- Hive SQL语法和标准SQL很类似,使得学习成本降低不少。
- Hive底层是通过MapReduce执行的数据插入动作,所以速度慢。
- 如果大数据集这么一条一条插入的话非常不现实,成本极高。
- Hive应该具有自己的数据插入表方式,结构化文件映射成为表。
创建一张表,添加分割符语法
create table t_user(id int,name verchar(255),age int,city varchar(255)) row format delimited fields terminated by',';
把user.txt文件从本地文件系统上传到hdfs
hdfs dfs -put user.txt /user/hive/warehouse/itcast.db/t_user/
执行查询操作
select * from t_user;
结论
要先在hive中创建表跟结构化文件映射成功,需要注意一下几个方面的问题:
创建表时,字段顺序,字段类型要和文件中保持一致。
如果类型不一致,hive会尝试转换,但是不保证转换成功,不成功为null.
Hive数据类型 Java数据类型 长度 例子 TINYINT byte 1byte 有符号整数 20 SMALINT short 2byte有符号整数 20 INT int 4byte有符号整数 20 BIGINT long 8byte有符号整数 20 BOOLEAN boolean 布尔类型,true或者false TRUE ,FALSE FLOAT float 单精度浮点型 3.14 DOUDBLE double 双精度浮点型 3.14 STRING string 支付系列。可以指定字符集,可以使用单引号或者双引号 ‘now is the time’ TIMESTAMP 时间类型 BINARY 直接数组 对于hive的string类型相当于数据库的varchar类型,该类型是一个可变的字符串,不过它不能声明最多能存储多少个字符,理论上它可以存储2GB的字符数
数据类型 描述 语法实例 STRUCT 和c预防struce类似,都可以通过“点"符合访问元素内容。例如如果某个列的数据类型是STRUCT{first STRING,last STRING},那么第一个元素可以通过字段.first来引用 struct() MAP MAP是一组件-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是Map,其中键->值对是‘first’->‘john’和’last‘->’Doe’,那么可以通过字段名[‘list’]获取最后一个元素 map() ARRAY 数组是一组具有相同类型和名称的变量集合,这些变量称为数据的元素,每个数据元素都有一个编号,编号从零开始。例如,数组值为[’john’,‘Doe’],那么第二个元素可以通过数据[1]进行引用 Array() Hive有三种复杂数据类型ARRAY、MAP和STRUCT。ARRAY和MAP与Java中的Array和Map类似,二STRUCT与c语言中的struct类似,它封装了一个命令字段集合,复杂数据类型允许任意层次的嵌套。
Hive原子数据类型是可以进行隐式转换的,类似于java的类型转换,例如某表达式是哟INT类型,TINYINT会自动转换为INT类型,但是HIve不会进行反向转换,例如吗,某表达式使用TINYINT类型,它会返回错误,除非使用CAST操作。
- 隐式转换类型规则如下
- 任何整数类型都可以隐式转换的转换为一个范围更广的类型,如TINYINT可以转换成INT,INT可以转换成BIGINT。
- 所有整数类型,FLOAT和STRING类型都可以隐式转换成DOUBLE。
- TINYINT、SMALLTNT、INT都可以转换为FLOAT.
- BOOLEAN类型不可以转换为任何其他的类型。
- 可以使用CAST操作显示进行数据类型转换。
- 例如CAST(1,ASINT)将字符串’1’转换成整数1;如果强制类型转换失败,如执行CAST('X’ASINT),表达式返回控制NULL.
- 数据定义语言,是SQL语言中集中对数据库内部的对象结构进行创建,删除,修改等操作语言,这些数据对象包括database、table、view、index等。
- DDL核心语法由CREATE、ALTER与DROP三个所组成。DDL并不涉及表内部数据的操作。
- 在某些上下文中,该术语也称为数据描述语言,因为它描述了数据库中的字段和记录。
- Hive数据类型指的是表中列的字段类型
- 整体分为两类:原生数据类型,和复杂数据类型
- 原生数据类型包括:数值类型,时间日期类型,字符串类型,杂项数据类型;
- 复杂数据类型包括:array数组,map映射,struct结构,union联合体。
注意事项
- Hive SQL中,数据类型英文字母大小不敏感;
- 除SQL数据类型外,还支持java数据类型,比如字符串String;
- 复杂数据类型的使用通常需要和分隔符指定语法配合使用;
- 如果定义的数据类型和文件不一致,Hive会尝试隐式转换,但是不保证成功。
SerDe是什么
- SerDe是Serializer、Deserializer的简称,目的是用于序列化和反序列化。
- 序列化是对象转化为字节码的过程;而反序列化是字节码转换为对象的过程。
- Hive使用SerDe(包括FileFormat)读取和吸入表行对象。需要注意的是,“key”部分在读取时会被忽略,而在吸入时key始终是参数,基本上行对象存储在“value”中。
Hive读文件流程
- Hive读取文件机制:首先调研InputFormat(默认TextInputFormat),返回一条一条kv键值对记录(默认是一行对应一条键值对)。然后调用SerDe(默认LazySimpleSerDe)的Deserializer,将一条记录中的value根据分隔切分为各个字段。
- Hive写文件机制:将Row吸入文件时,首先调用SerDe(默认LazySimleSerDe)的Serializer将对象转换成字节序列,然后调用OutputFormat将数据写入HDFS文件中。
LazySimpleSerDe分隔符指定
- LazySimpleSerDe是Hive默认的序列化类,包含4种语法,分别用于指定字段之间,集合元素之间,map映射 kv之间,换行的分隔符号。
- 在建表的时候可以根据数据的特点灵活搭配使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fNEHZ7M7-1666068736591)(C:\Users\云\AppData\Roaming\Typora\typora-user-images\image-20220930171805331.png)]
默认存储路径
- Hive表默认存储路径是由${HIVE_HOME} /conf/hive-site.xml配置文件的hive.metastore.warehouse.dir属性指定默认值是:/user/hive/warehouse。
指定存储路径
- 在Hive建表的时候,可以通过location语法来更改数据在HDFS上的存储路径,使得建表加载数据更加灵活方便。
- 语法:location ’
‘。 - 对于已经生成好的数据文件,使用location指定路径会很方便。
创建库
create database 库名;
查看库
show databases;
切换数据库
use 库命;
创建库,并指定存储位置
create database 库名 location '路径';
查询数据库结构
desc database 库名;
模糊查询
show databases like 'hive*';
修改数据库
用户可以使用ALTER DATABASE命令为某个数据库的DBPROPERTIES设置键-值对属性名和数据库所在的目录位置。 alter database db_hive set dbproperties('createtime'='20170830');
删除数据库
1、删除空数据库 drop database db_hive2; 2、如果删除的数据库不存在,最好此采用if exists 判断数据库是否存在 drop database if exists db_hive2; 3、如果数据库不为空,可以采用cascade命令,强制删除 drop database db_hive cascade;
1、建表语法
create [external] tanle [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_fomat] [stored as file_format] [location hdfs_path]
2、字段解释说明
1、create table 创建一个指定名字的表,如果相同名字的表已经存在,则抛出异常;用户可以用 if not exists 选项来忽略这个异常。 2、external 关键字可以让用户创建一个外部表,在创建的同时指定一个指向实际数据的路径(location),Hive创建内部表时,会将数据移动到数据仓库指向的路径,若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变,在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,部删除数据。 3、comment,为表和列添加注释。 4、partitioned by 创建分区表 5、clustered by 创建分桶表 6、sorted by 不常用 7、row format 用户在创建表的时候可以自定义serDe或者使用自带的serDe。如果没有指定ROWFORMAT或者 row format delimited ,将会使用自带的serDe,在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的serDe,hive通过serDe切丁表的躯体列的数据。SerDe是serialize/Deserilize的简称,目的是用于序列化的反序列化。 8、stored as 指定存储文件类型,常用的存储文件类型:sequencefile(二进制序列文件)、textfile(文本)、rcfile(列式存储格式文件)如果文件数据式纯文本,可以使用stored as textfile.如果数据需要压缩,使用stored as sequencefile. 9、location: 指定表在hdfs上存储的位置 10、like语序用户复制现有的表结构,但是不复制数据。
建表
create table 表名( name string, age int )
查看表
show tables;
查看指定表的元数据信息
describe formatted itheima.student_trans;
创建表结构
create table t_archer( id int comment "ID", name string comment "英雄名称", hp_max int comment "最大生命", mp_max int comment "最大法力", attack_max int comment "最高物攻", defense_max int comment "最打物攻", datack_range string comment "攻击范围", role_main string comment "主要定位", role_assist string comment "次要定位" )comment "王者荣耀射手信息"
向表中装载本地数据
load data local inpath '数据路径名' into table 表名;
向表中转hdfs数据
load data inpath '数据路径名' into table 表名;
删除表
drop table 表名; --删除表的元数据和数据 如果已经配置来几桶且未指定purge,则该表对应的数据实际上将移动到HDFS垃圾桶,而元数据完全丢失。删除external表时,该表中的数据不会从文件系统中删除,只删除元数据。 如果指定了purge,则表数据跳过hdfs垃圾桶直接被删除,因此如果drop失败,则无法挽回该表数据。
清空表
truncate table 表名; --可以简单理解为清空表的所有数据但是保留表的元数据结构。如果hdfs启动了垃圾桶,数据将被丢进垃圾桶,否则将被删除。
更改表名
alter table table_name Rename to new_table_name;
更多熟悉
--查询指定表的元数据信息 describe formatted itheima.student_partition; --1、更改表名 ALTER TABLE table_name RENAME TO new_table_name; --2、更改表属性 ALTER TABLE table_name SET TBLPROPERTIES (property_name = property_value, ... ); --更改表注释 ALTER TABLE student SET TBLPROPERTIES ('comment' = "new comment for student table"); --3、更改SerDe属性 ALTER TABLE table_name SET SERDE serde_class_name [WITH SERDEPROPERTIES (property_name = property_value, ... )]; ALTER TABLE table_name [PARTITION partition_spec] SET SERDEPROPERTIES serde_properties; ALTER TABLE table_name SET SERDEPROPERTIES ('field.delim' = ','); --移除SerDe属性 ALTER TABLE table_name [PARTITION partition_spec] UNSET SERDEPROPERTIES (property_name, ... ); --4、更改表的文件存储格式 该操作仅更改表元数据。现有数据的任何转换都必须在Hive之外进行。 ALTER TABLE table_name SET FILEFORMAT file_format; --5、更改表的存储位置路径 ALTER TABLE table_name SET LOCATION "new location"; --6、更改列名称/类型/位置/注释 CREATE TABLE test_change (a int, b int, c int); // First change column a's name to a1. ALTER TABLE test_change CHANGE a a1 INT; // Next change column a1's name to a2, its data type to string, and put it after column b. ALTER TABLE test_change CHANGE a1 a2 STRING AFTER b; // The new table's structure is: b int, a2 string, c int. // Then change column c's name to c1, and put it as the first column. ALTER TABLE test_change CHANGE c c1 INT FIRST; // The new table's structure is: c1 int, b int, a2 string. // Add a comment to column a1 ALTER TABLE test_change CHANGE a1 a1 INT COMMENT 'this is column a1'; --7、添加/替换列 --使用ADD COLUMNS,您可以将新列添加到现有列的末尾但在分区列之前。 --REPLACE COLUMNS 将删除所有现有列,并添加新的列集。 ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type,...);
修改表,更改表的属性
alter table table_name set tblproperties(property_name = property_value,...);
指定字段之间的分隔
row format delimited fields terminated by '\t';
指定集合之间的分隔符
row format delimited collection items terminated by '-';
指定map元素KV之间的分隔符
row format delimited map keys terminated by ':';
不指定分隔符使用默认的\001进行分隔
--没有采用row format语句 此时采用的是默认的\001作为字段的分隔符 create table t_team_ace_player( id int, team_name string, ace_player_name string );
使用location关键字指定本张表数据在hdfs上存储的路径
create table t_team_ace_player_location( id int, team_name string, ace_player_name string) location '/data' --使用location关键字指定本张表数据在hdfs上存储路径
创建外部表
create external table student_ext( // 创建外部表 num int, name string, )row format delimited fields terminated by ',' // 指定字段之间的分隔符 location '/stu'; // 指定外部表存储的位置
查询student2表的类型
desc formattd student2;
修改内部表student2为外部表
alter table student2 set tblproperties('EXTERNAL'='TRUE');
修改外部表student2为内部表
alter table student2 set tblproperties('EXTERNAL'='FALSE');
注意:(‘EXTERNAL’=‘TRUE’)和(‘EXTERNAL’=‘FALSE’)为固定写法,区分大小写
语法
load data [local] inpath '数据的path' [overwrite] into table student [partition (partcoll=vall,...)]
- load data:表示加载数据
- local:表示从本地加载数据到hive表;否则从hdfs加载数据到hive表
- inpath:表示加载数据的路径
- overwrite:表示覆盖表中已有的数据,否则表示追加
- into table:表示加载到哪张表
- student:表示具体的表
- partition:表示上传到指定的分区
1、创建一张表
cretate table student_par(id int,name string)row format delimited fields terminated by '\t'
2、基本插入数据
insert into table student_par value(1,'wangwu'),(2,'zhaoliu');
3、基本模式插入(根据单张表查询结果)
insert overwrite table student_par select id,name from student where month='201709';
insert into:以追加数据的方式插入到表或分区,原有数据不会删除
insert overwrite :会覆盖表中已存在的数据
注意:insert不支持插入部分字段
4、多表(多分区)插入模式(根据多张表查询结果)
from student insert overwrite table student partition(month='201707') select id,name where month='201709' insert overwrite table student partition(month='201706') select id,name where month='201709';
根据查询结果创建表(查询的结果会添加到新的表中)
create table if not exists student3 as select id,name from student;
注意:先用export导出后,在将数据导入。
import table student2 form '/user/hive/warehouse/export/student';
注意:这里的导出要慎用,因为有覆盖的关键词overwrite所以导入的文件夹一般不要存放文件,否则会覆盖该文件。
将查询的结果导出到本地
insert overwrite local directory '/opt/hive/datas/export/student' select * from student;
将查询的结果格式化导出到本地
insert overwrite local directory '/opt/hive/datas/export/student' row format delimited fields terminated by '\t'
将查询到的结果以\t分隔导出到hdfs上存储为orc文件格式(没有local)
insert overwrite directory '/user/atguigu/student2' row format delimited fields terminated by '\t' stored as orc select * from student;
dfs -get /user/hive/warehouse/student/student.txt /opt;
基本语法:(hive -f/-e 执行语句或者脚本 > file)
bin/hive -e 'select * from defaut.student;' >opt/
export table default.student to '/user/hive/warehouse/export/student';
它是直接将数据导入到MySQL当中的,后续在学习
注意:Truncate只能删除管理表,不能删除外部中数据
truncate table student;
select * from from emp; select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp;
select empno,ename from emp;
注意:
- sql语言大小写不敏感
- SQL可以卸载一行或者多行
- 关键字不能被缩写也不能分行
- 各子句一般要分行写。
- 使用缩进提高语句的可读性。
重命名一个列
便于计算
紧跟列明,也可以在列名之间加入关键字 ‘as’
案例实操
select ename as name,deptno dn from emp;
求总行数(count)
select count(*) cnt from emp;
求工资的最大值(max)
select max(sal) as max_sal from emp;
求工资的最小值(min)
select min(sal) as min_sal from emp;
求工资的总和(sum)
select sum(sal) as sum_sal from emp;
求工资的平均值(avg)
select avg(sal) as avg_sal from emp;
电信的查询会返回多行数据,Limit子句用于限制返回的行数。
select * from emp limit 5;
select * from emp limit 2,3;
使用where子句,将不满足条件的行过来掉
where子句紧随from子句
实例实操
查询出薪水大于1000的所有员工
select * from emp where sal > 1000;
注意:where之句不能使用字段别名
运算符 支持的数据类型 描述 a [not] between b and c 基本数据类型 如果a,b或者c任一为null,则结果为null,如果a的值大于等于b且小于或等于c,则结果为true,反之为false。如果使用not关键字则可以达到相反的 a is null 所有数据类型 如果a等于null,则返回true,反之返回false a is not null 所有数据类型 如果a不等于null,则返回true,反之返回false a [not] like b string b 是一个SQL下的简单正则表达式,也叫通配符模式,如果a与其匹配的话,则返回true,反之返回false.B的表达式说明如下:’x%'表示a必须以字母x开头,‘%x‘表示a必须以字母x结尾,而’%x%‘表示a包含字母x,可以位于开头,结尾或者字符串中间,如果是使用not关键字则可以达到相反的效果。 in(数值1,数值2) 所有数据类型 使用IN运算符显示列表中的值 案例实操
查询出薪水等于5000的所有员工
select * from emp where sal =5000
查询工资在500到1000的员工信息
select * from emp where sal between 500 and 1000;
查询comm为空的员工信息
select * from emp where comm is null;
查询工资是1500或者5000的员工信息
select * from emp where sal in(1500,5000);
使用like运算符选择类似的值
选择条件可以包含字符或数字:
%代表零个或多个字符(任意字符)
_代表一个字符
rlike子句
rlike子句是hive中这个功能的一个扩展,其可以通过java的正则表达式这个更强大的语言来指定匹配的条件。
案例实操
查找名字以A开头的员工信息
select * from emp where ename like 'A%';
查找名字中有第二个字母为A的员工信息
select * from emp where ename like '_A%';
查找名字中带A的员工信息
select * from emp where ename like '%A%'; select * from emp where ename rlike '[A]'; --跟上面意思是一样的
group by语句
group by语句通常会和聚合函数一起使用,按照一个或者多个列队进行分组,然后队每个组执行聚合操作
案例实操
- 计算emp表每个部门的平均工资
select t.deptno,avg(t.sal) as avg_sal from emp as t group by t.deptno;
- 计算emp每个部门后每个岗位的最高薪水
select t.deptno,t.job,max(t.sal) as max_sal from emp as t group by t.deptno;
hive支持通常的sql join语句。
案例实操
- 根据员工表和部门表中的编号相等,查询员工编号,员工名称和部门名称:
select e.empno,d.deptno,d.dname from emp as e join dept as d on e.deptno = d.deptno;
内连接:只有进行连接的两个表中都存在与连接条件相匹配的的数据才会被保留下来
select e.empno,d.ename,d.deptno from emp as e inner join dept as d on e.deptno = d.deptno;
左外连接:JOIN操作符左边表中符合where子句的所有记录将会被返回。
select e.empno,e.ename,d.deptno from emp as e left join dept as d on e.deptno = d.deptno;
右外连接:join操作字符右边表符合where子句的所有记录将会被返回。
select e.empno,e.ename,d.deptno from emp as e right join dept d on e.deptno = d.deptno;
满外连接:将会返回所有表中符合where语句条件的所有记录。如果任一表的指定字段没有符合条件的值得话,那么就使用null值替代。
select e.empno,e.ename,d.deptno from emp as e full join dept d on e.deptno = d.deptno;
笛卡尔积会在下面条件产生
- 省略连接条件
- 连接条件无效
- 所有表中的所有行互相连接
order by:全局培训,只有一个Reducer
使用order by子句排序
Asc :升序(默认)
desc : 降序
order by 子句在select语句的结尾
案例实操
查询员工信息工资升序排列
select * from emp order by sal;
查询员工信息按工资降序排列
select * from emp order by sal desc;
按照员工薪水的2倍排序
select ename,sal*2 as twosal from emp order by twosal;
按照部门和工资升序排序
select ename,deptno,sal from emp order by deptno,sal;
Sort By:对于大规模的数据集order by的效率非常低。在效率非常低。在很多情况下,并不需要全局排序,此时可以使用sort by。
Sort by为每个reducer产生一个排序文件。每个reduce内部进行排序,对全局结果集来说不是排序。
设置reduce个数
set mapreduce.job.reduces=3;
查看设置reduce个数
set mapreduce.job.reduces;
根据部门编号降序查看员工的信息
select * from emp sort by deptno desc;
将查询结果导入到文件中(按照部门变化降序排序)
insert overwrite local directory '/opt/module/hive/datas/sortby-result' --overwrite不能随便使用,一不小心就会覆盖原来的目录,容易丢失数据 select * from emp sort by deptno desc;
将查询结果导入到文件中(按照部门编号降序排序)
insert overwrite local directory --overwrite不能随便使用,一不小心就会覆盖原来的目录,容易丢失数据 '/opt/module/hive/datas/sortby-result' select * from emp sort by deptno desc;
理论
默认创建的表都是所谓的管理表,有时也称为内部表。因为这种表,hive会(或多或少地)控制着数据的生命周期。hive默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。当我们删除一个管理表时,Hive也会删除这个表中的数据。管理表不适合和其他共享数据。
什么是 内部表
- 内部表也称为被Hive拥有和管理的托管表
- 默认情况下创建的表就是内部表,Hive拥有该表的结构和文件,Hive完全管理表(元数据和数据)的生命周期,类似于RDBMS中的表。
- 当您删除内部表时,它会删除数据以及表的元数据。
什么是外部表
- 外部表中的数据不是Hive拥有或管理的,只管理表元数据的生命周期。
- 要创建一个外部表,需要使用external 语法关键字。
- 删除外部表只会删除元数据,而不会删除实际数据。在Hive外部仍然可以访问实际数据。
- 实际场景中,外部表搭配location语法指定数据的路径,可以让数据更安全。
内、外部表差异
- 无论内部表还是外部表,Hive都在Hive Metastore中管理表的定义,字段类型等元数据信息。
- 删除内部表时,除了会从Metastore中删除表元数据,还会从HDFS中删除所有数据文件。
- 删除外部表时,只会从Metastore中删除表的元数据,并保持HDFS位置中的实际数据不变。
内部表、托管表 外部表 创建方式 默认情况下 使用EXTERNAL语法关键字 Hive管理范围 元数据、表数据 元数据 删除表结果 删除元数据,删除HDFS上文件数据 只会删除元数据 操作 支持ARCHIVE,UNARCHIVE,TRUNCATE,MERGE,CONCATENATE 不支持 事务 支持ACID/事务性 不支持 缓存 支持结果缓存 不支持 如何选择内、外部表
- 当需要通过Hive完全管理控制表的整个生命周期时,请使用内部表。
- 当数据来之不易,防止误删,请使用外部表,因为即使删除表,文件会被保留。
- 在创建外部表的时候,可以使用location指定存储位置路径,如果不指定会如何
- 如果不指定location,外部表的默认路径也位于/user/hive/warehouse,由默认参数控制。
- 创建内部表的时候,是否可以使用location指定?
- 内部表可以使用location指定位置的。
- 是否意味着Hive表的数据在HDFS的位置不是一定要在/user/hive/warehouse下?
- 不一定,Hive中表数据存储位置,不管内部表还是外部表,默认都是在/user/hive、warehouse。当然可以在建表的时候通过location关键字指定存储位置在HDFS的任意位置上
--创建一个外部表 create external table student_ext( num int, name string, sex string, age int, dept string )row format delimited fields terminated by ',' location '/stu'; --指定表的存储路径
查看表是属于外部表还是内部表
describe formatted 库名.表名; --查看表的类型(库名可以字节省略)
概念
- 当Hive表对应的数据量大,文件个数多时,为了避免查询时全表扫描数据,Hive支持根据指定的字段对表进行分区,分区的字段可以是日期,地域,种类等具有标识意义的字段。
- 比如把一整年的数据根据月份划分12个月(12个分区),后续就可以查询指定月份分区的数据,尽可能避免了全表扫描查询。
背景
对于分区表的数据导入加载,最基础的是通过load命令加载数据。
在load过程中,分区值是手动指定写死的,叫做静态分区。
create table student_HDFS_p( Sno int, sname string, sex string, sage int, sdept string )partitioned by(country string) row format delimited fields terminated by ',' -- 注意 分区字段country的值是在导入数据的时候手动指定的China load data inpath '/student.txt' into table student_HDFS_p partition(country = 'China');
分区表数据加载–静态分区
所谓静态分区指的是分区的属性值由用户在加载数据的时候手动指定的。
语法如下:
load data [local] inpath 'filepath' into table tablename partition partition(分区字段='分区值...');
- Local参数用于指定待加载的数据是位于本地文件系统还是HDFS文件系统。关于load语句后续详细展开讲解。
分区案例
--创建分区表 --注意分区表语法规则 create table t_all_hero_part( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string )partitioned by(role string) --指定分区表的分区字段,这里不能于表中的字段重复 row format delimited fields terminated by '\t'; select * from t_all_hero_part; --将数据从本地加载到分区表中,并且设置每个表的分区字段的值,通过分区字段的值得不同进行分区 --静态加载分区表数据 load data local inpath '/root/a/archer.txt' into table t_all_hero_part partition(role='sheshou'); load data local inpath '/root/a/assassin.txt' into table t_all_hero_part partition(role="cike"); load data loca l inpath '/root/a/mage.txt' into table t_all_hero_part partition(role="fashi"); load data local inpath '/root/a/support.txt' into table t_all_hero_part partition(role="fuzhu"); load data local inpath '/root/a/tank.txt' into table t_all_hero_part partition(role="tanke"); load data local inpath '/root/a/warrior.txt' into table t_all_hero_part partition(role="zhanshi");
本质
- 分区的概念提供了一种将Hive表数据分离为多个文件/目录的方法。
- 不同分区对应着不同的文件夹,同一分区的数据在同一个文件夹下。
- 查询过滤的时候只需要根据分区值找对应的文件,扫描文件夹下本分区下得文件即可,避免全表数据扫描。
- 这种指定分区查询的方式叫做分区裁剪。
多重分区表
- 通过建表语句中关于分区的相关语法可以发现,Hive支持多个分区字段:PARTITIONRF BY
- 多重分区下,分区之间是一种地精关系,可以理解为在前一个分区的基础上继续分区。
- 从HDFS的角度来看就是文件夹下继续划分子文件夹。比如:把全国人口数据首先根据省进行区分,然后根据市进行划分,如果你需要甚至可以继续根据区在划分,此时就是3分区表。
双重分区表的使用
-- 分区字段之间是一种递进关系 因此要注意分区字段的顺序 谁在前在后 create table t_user_province_city(id int,name string,age int) partitioned by (province string,city string); -- 这里的参数谁在前色的分区就在前面 -- 将数据加载到分区表中 load data locat inpath '/root/hivedata/user.txt' into table t_user_province_city partition(province='zhejiang',city='ningbo'); .... -- 双分区表的使用 使用分区进行过滤 减少全表扫描 提高查询效率 select * from t_user_province_city where province='zhejiang' and city=、'hangzhou';
分区表数据加载——动态分区
所谓动态分区指的是分区的字段是基于查询结果(参数位置)自动推断出来的。核心语法就是insert + select。
启用hive动态分区,需要在hive 回话中设置两个参数:
#是否开启动态分区功能 set hive.exec.dynamic.partition=true; #指定动态分区模式,分为nanstick非严格模式和strict严格模式。 #strict严格模式要求至少有一个分区为静态分区 set hive.exec.dynamic.partition.mode=nonstrict;
动态分区的使用
--使用动态分区之前需要设置两个配置 set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; --创建一张新的分区表 t_all_he:ro_part_dunamic create table t_all_hero_part_dynamic( id int, name string, hp_max int, mp_max int, defense_max int, attack_range string, role_main string, role_assist string )partitioned by(role string) row format delimited fields termminated by '\t'; -- 执行动态分区插入(将另外一张表中查询出来的结果插入到指定的分区表中) insert into table t_all_hero_part_dynamic partition(role) -- 注意这里我们的分区值并没有手动写死指定 select tmp.*,tmp.role_mian from t_all_hero as tmp; -- 最后查询分区表,反向已经分好区了 select * from t_all_hero_part_dynamic;
分区表的注意事项
一、分区表不是建表的必要语法规则,是一种优化手段,可选;
二、分区字段不能是表中已有的字段,不 能重复;
三、分区字段是虚拟字段,其数据并不存在底层的文件中;
四、分区字段的切丁来自于用户价值数据手动指定(静态分区)或者根据查询结果位置自动推断(动态分区)
五、Hive支持多重分区,也就是说在分区的基础上继续分区,划分更加细粒度
概念
- 分桶表也叫做桶表,叫法源自建表语法中bucket单词,是一种用于优化查询而设计的表类型。
- 分桶表对应的数据文件在底层会被分解为若干部分,通俗老说就是被拆分称为若干个独立的小文件。
- 在分桶时,要指定根据那个字段将数据分为几桶(几部分)。
规则
- 分桶规则如下:桶编号相同的数据会被分到同一个桶当中。
Bucket number = hash_function(bucketing_column) mod num_buckets 分桶编号 =哈希方法(分桶字段) 取模 分桶个数
hash_function取决于分桶字段bucketing_column的类型;
1、如果是int类型,hash_function(int) == int;
2、如果是其他比如bigint,string或者复杂数据类型,hash_function比较棘手,将是从该类型派生的某个数字,比如hashcode值。
分桶表的创建
- 根据seate州把数据分为5桶,建表语句如下:
create table itheima.t_usa_covid19_bucket( count_date string, county string, state string, fips int, cases int, deaths int )clustered by(state)into 5 buckets; -- 分桶的字段一定要是表中已经存在的字段
在创建分桶表时,还可以指定分桶内的数据排序规则:
--根据state州分为5桶 每个桶内根据cases病例数倒序排序 create table itheima.t_usa_covid19_bucket_sort( count_date string, county string, state string, fips int, cases int, deaths int )clustered by(state) sorted by(cases desc) into 5 buckets; --指定每个内部根据cases倒序排序
分桶表的数据加载
--step1:开启分桶的功能呢 从hive2.0开始不在需要设置 set hive.enforce.bucketing=true; --step2:把元数据加载到普通hive表中 drop table if exists t_usa_covid19; create table itheima.t_usa_covid19( count_date string, county string, state string, fips int, cases int, deaths int )row format delimited fields terminated by ','; --将数据源上传到hdfs,t_usa_covid19表对应的路径下 -- hdfs dfs -put us-covid-counties.dat /user/hive/warehouse/itheima.db/t_usa_covid19; --step3:使用insert+select语法将数据加载到分桶表中, insert into t_usa_covid19_bucket select * from t_usa_covid19;
使用三个好处
- 基于分桶字段查询时,减少全表扫描
--基于分桶字段state查询来自于New York州的数据 --不在需要进行全表扫描过滤 --根据分桶的规则hash_function(New York)mod5计算出分桶编号 --查询指定分桶里面的数据,就可以找出结果 此时是分桶扫描而不是全表扫描 select * from t_usa_covid19_bucket where state="New York";
- JOIN时可以提高MR程序效率, 减少迪卡尔成绩数量(前提是join的等值是分桶的字段)
a join b on a.id =b.id
- 分桶表数据进行高效抽样
- 当数据量特别大时,对全体数据进行处理存在困难时,抽样就是显得尤为重要了,抽样可以从被抽取的数据中估计和推断出整体的特性,是科学实验,质量检验,社会调查普遍采用的一种经济有效的工作和研究方法。
虽然hive支持具有ACID语义的事务,但是在使用起来,并没有限MySQL中使用的那样方便,有很多局限性。原因很简单,毕竟hive的设计目标不是为了支持事务操作,而是支持分析操作,且最终基于hdfs的底层存储机制使得文件的增加删除修改操作需要懂一些小心思。
一、尚不支持begin,commit 和rollback.所有语言操作都是自动提交的。
二、仅支持orc文件格式(stored as orc)
三、默认情况下事务配置为关闭。需要配置参数开启使用。
四、表必须是分桶表,才可以使用事务功能
五、表参数transaction必须为true;
六、外部表不能称为acid表,不允许从非acid回话读取/写入acid表
Hive的文件是存储在HDFS上的,而HDFS上面不支持对文件的任意修改,只能是采取另外的手段来完成。
用HDFS文件作为元数据(基础数据),用delta保存事务操作的记录增量数据;
正在执行中的事务,是以一个staging开头的文件夹维护的,执行结束就是delta文件夹,每次执行一次事务操作都会有这样的一个delta增量文件夹;
当访问Hive 数据时,根据HDFS原始文件和delta增量文件做合并,查询最新的数据。
Insert语句会直接创建delta目录;
DELETE目录的前缀是delete_delta;
UPDATE语句采用了split-updata特性,即先删除、后插入;
实现原理之delta文件夹命名格式
- delta_minWID_maxWID_stmtID,即delta前缀,写事务的ID范围,以及语句ID;删除时前缀是delete_delta,里面包含了要删除的文件;
- Hive会写事务(insert、delete 等)创建一个写事务ID(WriteID),该ID在表范围内唯一;
- 语句ID(Statement ID)则是当一个事务中有多条写入语句时使用的,用作唯一标识。
- 每个事务delta文件夹下,都有两个文件:
- _orc_acid_version的内容是2,即当前ACID版本号是2,。和版本1主要的区别是update语句采用了split-update特性,即先删除、后插入。这个文件不是orc文件,可以下载下来直接查看。
- 随着表的修改操作,创建了越来越多的delta增量文件,就需要合并以保持足够的性能。
- 合并器Compactor是一套在Hive Metastore内运行,支持ACID系统的后台进程。所有合并都是在后台完成的,不会阻止数据的并发读,写。合并后,系统将等待所有旧文件的读操作完成后,删除旧文件。
- 黑冰操作分为两种,miner compaction(小合并)、ma jor compaction(小合并):
- 小合并会将一组delta增量文件重写为单个增量文件,默认触发条件为10个delta问阿金;
- 大合并将一个或多个增量文件和基础文件重写为新的基础文件,默认触发条件为delta文件相应基础文件占比,10%
虽然Hive支持了具有ACID语句的事务,但是在使用起来,并没有像在MySQL中使用那样方便,有很多限制;
- 尚不支持BEGIN,COMMIT 和 ROLLBACK,所有语言操作都是自动提交的;
- 表文件存储格式仅支持ORC(STORED AS ORC)
- 需要配置参数开启事务使用;
- 外部表无法创建为事务表,因为Hive只能控制元数据,无法管理数据;
- 表属性参数transactional必须设置为true;
- 必须将Hive事务管理器设置为org.apache.hadoop.hive.ql.lockmgr.DbTxnManager才能使用ACID表;
- 事务表不支持LOAD DATA …语句。
使用事务时需要先配置一下内容
--Hive中事务表的创建使用 --1、开启事务配置(可以使用set设置当前session生效 也可以配置在hive-siste.xml中) set hive.support.concurrency = true; --Hive是否支持并发 set hive.enforce.bucketing = true; --从Hive2.0开始不在需要 是否开启分桶功能 set hive.exec.dynamic.partition.mode = nonstrict;--动态分区模式 非严格 set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; set hive.compactor.initiator.on = true; --是否在Metastore实例上运行启动线程和清理线程 set hive.compactor.worker.threads = 1; --在此metastore实例上运行多少个压缩程序工作线程。
创建Hive事务表
--2、创建hive事务表 create table trans_student( id int, name String, age int )clustered by(id) into 2 buckets stored as orc TBLPROPERTIES ("transactional"='true'); -- 注意事务表的创建的几个要素,开启参数,分桶表,存储格式为orc ,表属性 -- clustered by(id) into 2 buckets 表示创建的是一个分桶表,分为2桶 --stored as orc 表示创建的表存储格式为orc -- TBLPROPERTIES ("transactional"='true') 表示表的属性transactional 设置为true 表示事务的开启
针对事务表进行insert update delete操作
insert into trans_student values(1,"allen",18); -- 插入数据
update trans_student set age = 20 where id = 1; --更新
delete from trans_student where id = 1; -- 删除
- Hive中的视图(view)是一种虚拟表,只保存定义,不实际存储数据。
- 通常从真实的物理表中创建生成视图,也可以从已经存在的视图上创建新视图。
- 创建视图时,将冻结视图的架构,如果删除或更改基础表,则视图将失败。
- 视图时用来简化操作的,不缓冲记录,也没有提供查询性能。
创建视图
create view v_usa_covid19 as select count_date,county,state,deaths from t_usa_covid19 limit 5;
查看视图
show views;
查看视图的定义(就是查询创建该视图的hql语句)
show create table v_usa_covid19;
- 将真实表中特定的列数据提供给用户,保护数据隐私
- 降低查询的复杂度,优化查询语句。
简要说明
物化视图的功能就是把需要物化出来的查询结果存储起来,等到下次有相同的查询要求,会直接返回此结果,这样可以减少查询的时间,大大增加查询的效率。
- 物化视图是一个包括查询结果的数据库对象,可以用于预先计算并保存表连接或聚集等耗时较多的操作结果。在执行结果查询时,就可以避免进行这些耗时的操作,而从快速的得到结果。
- 使用物化视图的目的就是通过预计算,提高奥查询性能,当然西药占用一定的存储空间。
概念
- Hive3.0开始尝试引入物化视图,并提供对于物化视图的查询自动重写机制(基于Apache Calcite实现)。
- Hive的物化视图还提供了物化视图存储机制,可以本地存储在Hive,也可以通过用户自定义storage handlers 存储在其他系统 (如druid).
- Hive引入物化视图的目的就是为了优化数据查询访问的效率,相当于预处理的角度优化数据访问。
- Hive从3.0丢弃了index索引的语法支持,推荐使用物化视图和列式存储文件格式来加快查询的速度。
物化视图、视图的区别
- 视图时虚拟的,逻辑存在的,只有定义没有存储数据。
- 物化视图时真实的,物理存在的,里面存储着预计算的数据。
- 物化视图能够缓存数据,在创建物化视图的时候就把数据缓存起来了,Hive把物化视图当成一张表,将数据缓存。而视图只是创建一个虚拟表,只有表结构,没有数据,实际查询的时候在去改写SQL去访问实际的数据表。
- 视图的目的是简化降低查询的复杂度,而物化视图的目的是提高查询性能。
基于物化视图的查询重写
物化视图创建后即可用相关查询的加速,即:用户提交查询query,若该query经过重写后可以命中已经存在的物化视图,则直接通过物化视图查询数据返回结果,以实现查询加速
是否重写查询使用物化视图查询重写机制,默认为true:hive.materializedview.rewriting=true;
用户可以选择性的控制指定的物化视图查询重写机制,语法如下:
alter materialized view [db_name.]materialized_view_name enable|disable rewrite;
物化视图的使用
--使用物化视图之前要先开启一下功能 --1、开启事务配置(可以使用set设置当前session生效 也可以配置在hive-siste.xml中) set hive.support.concurrency = true; --Hive是否支持并发 set hive.enforce.bucketing = true; --从Hive2.0开始不在需要 是否开启分桶功能 set hive.exec.dynamic.partition.mode = nonstrict;--动态分区模式 非严格 set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; set hive.compactor.initiator.on = true; --是否在Metastore实例上运行启动线程和清理线程 set hive.compactor.worker.threads = 1; --在此metastore实例上运行多少个压缩程序工作线程。 --创建一个事务表 create table student_trans( sno int, sname string, sdept string )clustered by (sno) into 2 buckets stored as orc tblproperties('transactional'='true'); -- 创建一个物化视图 --3、对student——trans建立聚合物化视图,这里把执行完的语句存储起来,下一就不用查询了直接使用这里的查询结果就可以了 create materialized view student_trans_agg as select sdept,count(*) as sdept_cnt from student_trans group by sdept;
可以通过使用下面语句进行查看物化视图是否创建好了
show tables; show materialized views;
由于会命中物化视图,重写query查询物化视图,查询速度会加快没有启动mr,只是普通的table scan)
--4对原始表student_trans查询 --由于会命中物化视图,重写query查询物化视图,查询速度会加快(没有启动mr,只是普通的table scan) select sdept,count(*) as sdept_cnt from student_trans group by sdept;
禁用物化视图自动重写
alter materialized view student_trans_agg disable rewrite;
删除物化视图
drop materialized view student_trans_agg;
add partition 增加分区
- add partition会更改表元数据,但不会加载数据。如果分区位置中不存在数据,查询时将不会返回结果。
- 因此需要保证增加的分区位置路径下,数据已经存在,或者增加完分区之后导入分区数据。5
--1、增加分区 alter table table_name add partition(dt='20170101')location '/user/hadoop/warehouse/table_name/dt=20170101'; --一次添加一个分区 alter table table_name add pattition(dt='2008-08-08',country='us')location '/path/to/us/part080808' partition(dt='2008-08-09',country='us')location'/path/to/us/part080809'; --一次添加多个分区
rename partition 重命名分区
--2、重命名分区 alter table table_name partition partition_spec rename to Partition partition_spec;
delete partition 删除分区
--3、删除分区 alter table table_name drop if exists partition (dt='2008-08-08',country='us') alter table table_name drop if exists partition (dt='2008-08-08',country='us')purge --直接删除数据不进垃圾桶
msck parririon 背景
hive将每个表的分区列信息存储在其metastore中,但是,如果将新分区直接添加到hdfs(例如通过使用hadoop fs -put命令)或从hdfs中直接删除分区文件夹,则除非用户alter table table_name add/drop partition在每个新添加的分区上运行命令,否则metastore(也就是hive)将不会意识到分区信息的这些更改。
MSCK是metastore check的缩写,表示元数据检查操作,可用于元数据的修复。
--4.修复分区 msck [pepair] table table_name [add/drop/sync partitions];
show 语法
整体概述
- show 相关的语句提供了一种查询hvie metastore的方法,可以帮助用户查询相关信息。
- 比如我们最常使用的查询当前数据库下有哪些表 show tables.
--1、显示所有数据库 schemas和databases 的用法,功能一样。 show databases; show schemas; --2、显示当前数据库所有表/视图/物化视图/分区/索引 show tables; show tables [in database_name]; -- 指定某个数据库 --3、显示当前数据库下所有视图 show views; shwo views 'test_*'; show views from test1; --show views from database test1 shwo views [IN/from database_name]; --4、显示当前数据库下所有物化视图 show materialized views [in/from database_name]; -- 5、显示表的分区信息,分区按字母顺序列出,不是分区表执行该语句会报错。 show partitions table_name; show partitions itheima.student_partition; --6、显示表/分区的扩展信息 show table extended [in | from database_name] like table_name; show table extended like student; describe formatted itheima.student; --7、显示表的属性信息 show tblproperties table_name; show tblproperties student; --8、显示表、视图的创建语句 show create table([db_name]table_name|view_name) show create table student; --9、显示表中的所有列,包括分区列。 show colummns (from|in) table_name [(from|in) db_name]; shwo columns in student; --10、显示当前支持的所有自定义和内置的函数 show functions; --11、describe desc --查看表信息 --desc extended table_name; --查看表信息(格式化美观) desc fromatted table_name; --查看数据库相关信息 describe database database_name;
Local本地在哪里
本地文件系统指定是Hiveserver2服务所在的机器的本地Linux文件系统,不是Hive客户端所在的本地文件系统。
load 从本地的文件加载是复制文件操作
load 从hdfs上加载是执行移动文件操作
语法
load data local inpath '/root/file/students.txt' into table student.txt
Load Hive 3.0的新特性
- hive3.0+,load加载数据时除了移动、复制操作之外,在某些场合下还会将加载重写为insert as select .
- Hive3.0+,还支持使用inputformat、serDe指定输入格式,例如Text,ORC等
- 比如,如果表具有分区,则load命令没有指定分区,则将load转换为Insert as select,并假定最后一组列为分区列,如果文件不符合预期,则报错。
- insert+select 表示:将后面查询返回的结果作为内容插入到指定表中,注意overwrite将覆盖已有数据。
- 需要保证查询结果列的数目和需要插入数据表格的列数目一致。
- 如果查询出来的数据类型和插入表格对应的列数据类型不一致,将会进行转换,但是不能保证转换一定成功,转换失败的数据将会为NULL
insert into table t_student select * from t_user;
multiple inserts多重插入
翻译为多次插入,多重插入,其核心功能是:一次扫描,多次插入。
语法目的就是减少扫描的次数,在一次扫描中,完成多次insert操作。
--创建两个空表 create table t_student4( num int ); create table t_student5( name string ); --使用多重插入模式给两张表分别插入对应的数据 from t_student insert into t_student5 select name insert into t_student4 select num;
cluster by
根据指定字段将数据分组,每组内在根据字段正序排序(只能正序)。
概况起来就是:根据同一个字段,分且排序。
分组规则hash散列(分桶表规则一样):Hash_Func(col_name) % reducetask个数
分为几组取决于reducetask的个数
--根据在学生表中,根据性别进行分组,在进行排序 select * from student cluster by sex ;
distribute by + sort by
- distribute by + sort by 就相当于吧cluster by的功能一分为二:
- distribute by 负责根据指定字段分组;
- sort by负责分组内排序规则。
- 分组和排序的字段可以不同。
--案例:把学生表数据根据性别分为两部分,每个组内根据年龄的倒序排序。 select * from student distribute by sex sort by age desc;
- 如果distribute by + sort by 的字段一样,则:cluster by =distribute by + sort by
--下面两个语句执行结果一样 select * from student distribute by num sort by num; select * from student cluster by num;
cluster、distribute、sort、order by
- order by 全局排序,因此只有一个reducer,结果输出在一个文件中,当输入规模大时,需要较长的计算时间。
- distribute by 根据指定字段将数据分组,算法是hash散列。sort by 是在分组之后,每个组内局部排序。
- cluster by 即有分组,又有排序,但是两个字段只能是同一个字段。
如果distribute 和 sort 的字段是同一个时,此时,cluster by = distribute by + sort by
union用于将多个select 语句的结果合并为一个结果集。
- 使用distinct关键字与使用union默认值效果一样,都会删除重复行。1.2.0之前的hive版本仅支持union all ,在这种情况下不会消除重复的行。
- 使用all关键字,不会删除重复行,结果集包括所有select语句的匹配行(包括重复行)
- 每个select_statement返回的列的数量和名称必须相同。
--默认写法union会删除重复行 select num,name from student1 union select num,name from student2 --带参数distinct也会删除重复行 select num,name from student1 union distinct select num,name from student2 --如果使用union不想删除重复行的话可以加上all关键字 select num,name from student1 union all select num,name from student2 --如果要讲order by,sort by,cluster by,distribute by或limit引用于单个select --请将子句放在括住select的括号内,并给查询出来的表的结果起一个别名 select num,name from (select num,name from t_student2 limit 2) subq1 union select num,name from (select num,name from t_student3 limit 3)subq2; --如果要将order by,sort by,cluster by,distribute by 或limit子句应用于整个union结果 --请将order by,sort by, cluster by,distribute by 或limit放在最后一个之后。 select num,name from t_student2 union select num,name from t_student3 order by num desc;
在hive0.12版本,仅在from子句支持子查询。
必须要给子查询一个名称,因为from子句中的每个表都必须有一个名称。子句查询返回结果中的列必须具有唯一性的名称。子查询返回结果中的列在外部查询中可用,就像真实表的列一样。子查询也可以是带有union的查询表达式。
Hive支持任意级别的子查询,也就是所谓的嵌套子查询。
Hive 0.13.0和更高版本中的子查询名称之前可以包含可选关键字AS.
--from之句中子查询 --子查询 select num from( select num,namefrom student_local )tmp; --包含union all的子查询的实例 select t3.name from( select num,name from student_local union distinct select num,name from student_hdfs )t3; -- 这里from的子查询的表一定要起别名,否则会报错
从Hive 0.13开始,where子句支持下述类型的子查询:
- 不相关子查询:该子查询不引用父查询的列,可以将查询结果视为in和not in语句的常量;
- 相关子查询:子查询引用父查询中的列;
--where 之句中子查询 --不相关子查询,相当于IN,NOT IN,子查询只能选择一列。 --(1)执行子查询,其结果不被显示,而是传递给外部查询,作为外部查询的条件使用。 --(2)执行外部查询,并显示整个结果 select * from student_hdfs where student_hdfs.num IN(select num from student_local limit 2); --相关子查询,指EXISTS和NOT EXISTS子查询 --子查询的where子句中支持对父查询的引用 select A from t1 where exists(select b from t2 where t1.x = t2.y);
- 公用表达式(CTE)是一个临时结果集:该结果集是从with子句中指定的简单查询派生而来的,紧接在select或insert关键字之前。
- CTE仅在单个语句的执行范围内定义。
- CTE可以在select,insert,create table as select 或 create view as select 语句中使用
--临时结果集 --将查询的结果存储到一个q1的临时结果当中,需要子查询的时候可以直接使用q1进行查询。 with q1 as (select num,name,age from student where num = 95002) select * from q1; --from 风格 with q1 as (select num,name,age from student where num = 95002) from q1 select * ; --chaining CTEs链式 with q1 as (select * from student where num = 95002), q2 as (select num,name,age from q1) select * from (select num from q2) a; --union with q1 as (select * from student where num = 95002), q2 as (select * from student where num = 95004) select * from q1 union all select * from q2;
- 内连接是最常见的一种连接,它也被称为普通连接,其中inner可以省略:inner join ==join;
- 只有进行连接的两个表中都存在与连接条件相匹配的数据才会被留下来。
select e.deptno, e.ename, e.job from emp e join dept d on e.deptno = d.deptno;
- left join中文叫做是左外连接或者左连接,其中outer可以省略,left outer join是早期的写法。
- left join 的核心就在于left左。左指的是join关键字左边的表,简称左表。
- 通俗解释:join时以左表的全部数据为准,右边与之关联;左表数据全部返回,右表关联上的显示返回,关联不上的显示null返回。
select e.deptno, e.ename, e.job from emp e left join dept d on e.deptno = d.deptno;
- right join中文叫做是右外连接或者右连接,其中outer可以省略。
- right join的核心就在于Right右,右指的是join关键字右边的表,简称右表,
- 通俗解释:join时以右表的全部数据为准,左边与之关联;右表数据全部返回,左表关联不上的显示null返回。
- 很明星啊,right join和left join之间很相似,重点在于以那边为准,也就是一个反向的问题。
- fill outer join等价 full join ,中文叫做全外连接或者外连接。
- 包括左、右两个表的全部行,不管另外一边的表中是否存在他们匹配的行;
- 在功能上:等价与对这两个数据集合分别进行左外连接和右外连接,然后再使用消去重复行的操作间上述两个结果集合合并为一个结果集。
- 简单来讲就是查询了两张表,但是需要吧俩个表之间重复的消除掉。
- 左半开连接(left semi join)会返回左边表的记录,前提是其记录对于右边的表满足on语句中的判断条件。
- 从效果上来看有点像inner join之后只返回左表的结果。
select * from employee e left semi join employee_address e_addr on e.id = e_addr.id;
- 交叉连接 cross join,将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘机。对于大表来说,cross join慎用
- 在SQL标准中定义的cross join就是无条件的inner join。返回两个表的笛卡尔积,无需指定关联键。
- 在HiveSQL语法中,cross join 后面可以跟where子句进行过滤,或者on条件过滤。
- 允许使用复杂的连接表达式,支持非等值连接
select a.* from a join b on(a.id = b.id) select a.* from a join b on(a.id = b.id and a.department= b.department) select a.* from a left outer join b on (a.id <> b.id);
- 同一查询中可以连接2个以上的表
select a.val,b.val from a join b on (a.key = b.key1)join c on (c.key = b.key2)
如果每个表在连接子句中使用相同的列,则hive将多个表上的连接转换为单个MR作业
join时的最后一个表会通过reducer流式传输,并在其中缓冲之前的其他表,因此,将大表放置在最后有助于减少reducer阶段缓存数据说需要的内存
Hive CLI
Hive第一代客户端bin/hive
$HIVE_HOME/bin/hive 是一个shell util ,通常称之为Hive的第一代客户端或者旧客户端,主要功能有两个:
交互式或批处理模式运行Hive查询,注意,此时作为客户端,需要并且能够访问的是hive metastore服务,而不是hiveserver2 服务。
hive相关服务的启动,比如metastore 服务。
可以通过运行“hive -H” 或者 “hive --help” 来查看命令行选项。
-e <quoted-query-string> --执行命令行-e参数后指定的sql语句 运行完退出 -f <filename> --执行命令行-f参数后指定的sql文件 运行完退出 -H,-help --打印帮助信息 --hiveconf
--设置参数 -S,--silent --静默模式 -v, -verbose --详细模式,将执行sql回显到console -service service_name --启动hive的相关服务Hive第二代客户端bin/beeline
- $HIME_HOME/bin/beeline被称之为第二代客户端或者新客户端,是一个JDBC客户端,是官方强烈推荐使用的hive命令行工具。和第一代客户端相比,性能加强安全性提高。Beeline在嵌入式模式和远程模式下均可工作。
- 在嵌入式模式下,它运行嵌入式HIve(类似于hive CLI)
- 远程模式下beeline通过thrift连接到单独的hiveserver2服务上,这也是官方推荐在生产环境中使用的模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-suZ4BELm-1666068736593)(C:\Users\26965\AppData\Roaming\Typora\typora-user-images\image-20221007214207475.png)]
配置方式优先级
set设置 > hiveconf 参数 >hive-site.sml配置文件
set 参数声明会覆盖命令行参数hiveconf,命令行参数会覆盖配置文件hive-site.xml设定
日常开发使用中,如果不是核心的需要全局修改的参数属性,建议使用set命令进行设置
另外,Hive也会读入Hadoop的配置,因为Hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置
配置文件使用的官网
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
概述
整体上,Hive支持的运算符可以分为三大类:算数运算符、关系运算符、逻辑运算符
官方参考文档
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
- 也可以使用下述方式查看运算符的使用方式
显示所有的运算符和函数
show functions;
查看运算符或者函数的使用说明
describe function +;
关系运算符
空值判断 is null 非控制判断 is not null like 比较 like java的like 操作 rlike --1、创建表dual create table dual(id string); --2、加载一个文件dual.txt到dual表中 --dual.txt只有一行内容:内容为一个空格 load data local inpath '/root/file/dual.txt' into table dual; --3、在select查询语句中使用dual表完成运算符、函数功能测试 select 1+1 from dual; select 1+1;-- 新版本的hive是可以省略到from的 -- 否定比较:not a like b select 1 from dual where 'itcast' like 'it_'; select 1 from dual where 'itcast' like 'it%'; select 1 from dual where 'itcast' not like 'hadoo_'; select 1 from dual where not 'itcast' like 'hadoo_'; --rlike:确定字符串是否匹配正则表达式,是REGEXP_LIKE()的同义词。 select 1 from dual where 'itcast' rlike '^i.*t$'; --判断是否是以t结尾 select 1 from dual where '123456' rlike '^\\d+$'; --判断是否全为数字 select 1 from dual where '123456aa' rlike '^\\d+$'; --regexp :功能与rlike相同用于判断字符串是否是否匹配正则表达式 select 1 from dual where 'itcast' regexp '^i.*t$';
算数运算符
- 算数运算符操作数必须四数值类型。分为一元运算符和二元运算符:
- 一元运算符吗,只有一个操作数;二元运算符有两个操作数,运算符在两个操作数之间。
取证操作 div 取余操作 % 位与操作 & 位或操作 | 位异或操作 ^ --去整操作:div 给出将A除以B所得的整数部分。例如17 div 3得出5. select 17 div 3; --取余操作:%也叫做取模mod A除以B所得的余数部分 select 17 % 3; --位与操作:& A和B按位进行与操作的结果。与表示两个个都为1则结果为1 select 4 & 8 from dual; --4转换二进制:0100 8转换二进制:1000 select 6 & 4 from dual; --4转换二进制:0100 6转换二进制:0110 --位或操作: | A和B按位进行或操作的结果 或表示有一个为1则结果为1 select 4 | 8 from dual; --4转换二进制:0100 8转换二进制:1000 select 6 | 4 from dual; --4转换二进制:0100 6转换二进制:0110 --位或操作:^ A和B按位进行异或操作的结果 异或表示两者的值不同,则为1 select 4 ^ 8 from dual; --4转换二进制:0100 8转换二进制:1000 select 6 ^ 4 from dual; --4转换二进制:0100 6转换二进制:0110
逻辑运算符
与操作 A and b 或操作 A or B 非操作 not A != A 在 A in(val1,val2,…) 不在 not in(val1,val2,…) 逻辑是否存在 [not] exiss (subquery) 案例
--3、Hive逻辑运算符 --与操作:A and B 如果A和B均为TRUE,则为TRUE,否则为FALSE.如果A或B为NULL,则为NULL. select 1 from dual where 3>1 and 2>1; --或操作:A or B 如果A或B两者均为TRUE,则为TRUE,否则为FALSE. select 1 from dual where 3>1 or 2!=2; --非操作:not a != A 如果a为false,则为true;如果a为Null,则为Null.否则为false. select 1 from dual where not 2 > 1; select 1 from dual where !2=1; --在:A in(val1,val2,...) 如果A任何值,则为True select 1 from dual where 11 not in(22,33,44); --逻辑是否存在:[NOT] EXISTS (subquery) --将主查询的数据,放到子查询中左条件验证,根据验证结果(true 或false)来决定主查询的数据结果是否得以保留。 select A.* from abs() where exists (select B.id from B where A.id =B.id);
Hive的函数分为两大累:内置函数、用户自定义函数:
- 内置函数可分为:数值类型函数、日期类型函数、字符串类型函数、集合函数、条件函数等;
- 用户定义函数根据输入输出的行数可分为3类:UDF、UDAF、UDTF
- 根据函数输入输出的行数:
- UDF普通行数,一进一出
- UDAF聚合函数,多进一出
- UDTF表生成函数,一进多出
--查看当下可用的所有函数; show functions; --查看函数的使用方式。 describe function extended funcname;
- 内置函数指的是Hive开发实现好,直接可以使用的函数,也叫做内建函数。
- 官方文档地址:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
- 内置函数根据应用归类整体可以分为8大种类型,我们将其中重要的,使用频率高的函数使用进行详细讲解。
字符串函数
(非常重要的函数)
函数作用 函数名称 字符串连接函数 concat 带风格符字符串连接函数 concat_ws 字符串截取函数 substr,substring 正则表达式替换函数 regexp _replace URL解析函数 parse url json 解析函数 get json object f分割字符串函数 split (比较常用的函数)
函数作用 函数名称 字符串长度函数 length 字符串反转函数 reverse 字符串转大写函数 upper,ucase 字符串转小写函数 lower,lcase 去空格函数 trim 左边去空格函数 ltrim 右边去空格函数 rtrim 正则表达式解析函数 regexp extract 空格字符串函数 space 重复字符串函数 repeat 首字母ascii函数 ascii 左补足函数 lpad 右补足函数 rpad 集合查找函数 find in set 字符串函数案例
------------String Functions 字符串函数------------ select concat("angela","baby"); --带分隔符字符串连接函数:concat_ws(separator, [string | array(string)]+) select concat_ws('.', 'www', array('itcast', 'cn')); --字符串截取函数:substr(str, pos[, len]) 或者 substring(str, pos[, len]) select substr("angelababy",-2); --pos是从1开始的索引,如果为负数则倒着数 select substr("angelababy",2,2); --正则表达式替换函数:regexp_replace(str, regexp, rep) select regexp_replace('100-200', '(\\d+)', 'num'); --正则表达式解析函数:regexp_extract(str, regexp[, idx]) 提取正则匹配到的指定组内容 select regexp_extract('100-200', '(\\d+)-(\\d+)', 2); --URL解析函数:parse_url 注意要想一次解析出多个 可以使用parse_url_tuple这个UDTF函数 select parse_url('http://www.itcast.cn/path/p1.php?query=1', 'HOST'); --分割字符串函数: split(str, regex) select split('apache hive', '\\s+'); --json解析函数:get_json_object(json_txt, path) --$表示json对象 select get_json_object('[{"website":"www.itcast.cn","name":"allenwoon"}, {"website":"cloud.itcast.com","name":"carbondata 中文文档"}]', '$.[1].website'); --字符串长度函数:length(str | binary) select length("angelababy"); --字符串反转函数:reverse select reverse("angelababy"); --字符串连接函数:concat(str1, str2, ... strN) --字符串转大写函数:upper,ucase select upper("angelababy"); select ucase("angelababy"); --字符串转小写函数:lower,lcase select lower("ANGELABABY"); select lcase("ANGELABABY"); --去空格函数:trim 去除左右两边的空格 select trim(" angelababy "); --左边去空格函数:ltrim select ltrim(" angelababy "); --右边去空格函数:rtrim select rtrim(" angelababy "); --空格字符串函数:space(n) 返回指定个数空格 select space(4); --重复字符串函数:repeat(str, n) 重复str字符串n次 select repeat("angela",2); --首字符ascii函数:ascii select ascii("angela"); --a对应ASCII 97 --左补足函数:lpad select lpad('hi', 5, '??'); --???hi select lpad('hi', 1, '??'); --h --右补足函数:rpad select rpad('hi', 5, '??'); --集合查找函数: find_in_set(str,str_array) select find_in_set('a','abc,b,ab,c,def');
日期函数案例
--获取当前日期: current_date select current_date(); --获取当前时间戳: current_timestamp --同一查询中对current_timestamp的所有调用均返回相同的值。 select current_timestamp(); --获取当前UNIX时间戳函数: unix_timestamp select unix_timestamp(); --日期转UNIX时间戳函数: unix_timestamp select unix_timestamp("2011-12-07 13:01:03"); --指定格式日期转UNIX时间戳函数: unix_timestamp select unix_timestamp('20111207 13:01:03','yyyyMMdd HH:mm:ss'); --UNIX时间戳转日期函数: from_unixtime select from_unixtime(1618238391); select from_unixtime(0, 'yyyy-MM-dd HH:mm:ss'); --日期比较函数: datediff 日期格式要求'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd' select datediff('2012-12-08','2012-05-09'); --日期增加函数: date_add select date_add('2012-02-28',10); --日期减少函数: date_sub select date_sub('2012-01-1',10); --抽取日期函数: to_date select to_date('2009-07-30 04:17:52'); --日期转年函数: year select year('2009-07-30 04:17:52'); --日期转月函数: month select month('2009-07-30 04:17:52'); --日期转天函数: day select day('2009-07-30 04:17:52'); --日期转小时函数: hour select hour('2009-07-30 04:17:52'); --日期转分钟函数: minute select minute('2009-07-30 04:17:52'); --日期转秒函数: second select second('2009-07-30 04:17:52'); --日期转周函数: weekofyear 返回指定日期所示年份第几周 select weekofyear('2009-07-30 04:17:52');
数学函数
----Mathematical Functions 数学函数------------- --取整函数: round 返回double类型的整数值部分 (遵循四舍五入) select round(3.1415926); --指定精度取整函数: round(double a, int d) 返回指定精度d的double类型 select round(3.1415926,4); --向下取整函数: floor select floor(3.1415926); select floor(-3.1415926); --向上取整函数: ceil select ceil(3.1415926); select ceil(-3.1415926); --取随机数函数: rand 每次执行都不一样 返回一个0到1范围内的随机数 select rand(); --指定种子取随机数函数: rand(int seed) 得到一个稳定的随机数序列 select rand(3); --二进制函数: bin(BIGINT a) select bin(18); --进制转换函数: conv(BIGINT num, int from_base, int to_base) select conv(17,10,16); --绝对值函数: abs select abs(-3.9);
集合函数
-------Collection Functions 集合函数-------------- --集合元素size函数: size(Map
) size(Array select size(`array`(11,22,33)); select size(`map`("id",10086,"name","zhangsan","age",18)); --取map集合keys函数: map_keys(Map) ) select map_keys(`map`("id",10086,"name","zhangsan","age",18)); --取map集合values函数: map_values(Map) select map_values(`map`("id",10086,"name","zhangsan","age",18)); --判断数组是否包含指定元素: array_contains(Array, value) select array_contains(`array`(11,22,33),11); select array_contains(`array`(11,22,33),66); --数组排序函数:sort_array(Array) select sort_array(`array`(12,2,32));条件函数
-----Conditional Functions 条件函数------------------ --使用之前课程创建好的student表数据 select * from student limit 3; describe function extended isnull; --if条件判断: if(boolean testCondition, T valueTrue, T valueFalseOrNull) select if(1=2,100,200); select if(sex ='男','M','W') from student limit 3; --空判断函数: isnull( a ) select isnull("allen"); select isnull(null); --非空判断函数: isnotnull ( a ) select isnotnull("allen"); select isnotnull(null); --空值转换函数: nvl(T value, T default_value) select nvl("allen","itcast"); select nvl(null,"itcast"); --非空查找函数: COALESCE(T v1, T v2, ...) --返回参数中的第一个非空值;如果所有值都为NULL,那么返回NULL select COALESCE(null,11,22,33); select COALESCE(null,null,null,33); select COALESCE(null,null,null); --条件转换函数: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end; select case sex when '男' then 'male' else 'female' end from student limit 3; --nullif( a, b ): -- 如果a = b,则返回NULL,否则返回一个 select nullif(11,11); select nullif(11,12); --assert_true(condition) --如果'condition'不为真,则引发异常,否则返回null SELECT assert_true(11 >= 0); SELECT assert_true(-1 >= 0);
类型函数
----Type Conversion Functions 类型转换函数----------------- --任意数据类型之间转换:cast select cast(12.14 as bigint); select cast(12.14 as string); select cast("hello" as int);
数据脱敏函数
----Data Masking Functions 数据脱敏函数------------ --mask --将查询回的数据,大写字母转换为X,小写字母转换为x,数字转换为n。 select mask("abc123DEF"); select mask("abc123DEF",'-','.','^'); --自定义替换的字母 --mask_first_n(string str[, int n] --对前n个进行脱敏替换 select mask_first_n("abc123DEF",4); --mask_last_n(string str[, int n]) select mask_last_n("abc123DEF",4); --mask_show_first_n(string str[, int n]) --除了前n个字符,其余进行掩码处理 select mask_show_first_n("abc123DEF",4); --mask_show_last_n(string str[, int n]) select mask_show_last_n("abc123DEF",4); --mask_hash(string|char|varchar str) --返回字符串的hash编码。 select mask_hash("abc123DEF");
其他杂项函数
----- Misc. Functions 其他杂项函数--------------- --如果你要调用的java方法所在的jar包不是hive自带的 可以使用add jar添加进来 --hive调用java方法: java_method(class, method[, arg1[, arg2..]]) select java_method("java.lang.Math","max",11,22); --反射函数: reflect(class, method[, arg1[, arg2..]]) select reflect("java.lang.Math","max",11,22); --取哈希值函数:hash select hash("allen"); --current_user()、logged_in_user()、current_database()、version() --SHA-1加密: sha1(string/binary) select sha1("allen"); --SHA-2家族算法加密:sha2(string/binary, int) (SHA-224, SHA-256, SHA-384, SHA-512) select sha2("allen",224); select sha2("allen",512); --crc32加密: select crc32("allen"); --MD5加密: md5(string/binary) select md5("allen");
- 用户自定义函数简称UDF,源自英文user-defined function.
- 根据函数输入输出的行数可以分为3类,分别是:
- UDF普通函数,一进一出
- UDAF聚合函数,多进一出
- UDTF表生成函数,一进多出
UDF普通函数
- UDF普通函数
- 比如round这样的取整函数,接收一行数据,输出的还是一行数据。
UDAF聚合函数
UDAF聚合函数,A所代表的单词就是Aggregation聚合的意思
多进一出,也就是输入多行输出一行。
比如count,sum这样的函数 。
count :统计检索到的总行数
sum :求和
avg :求平均值
min :最小值
max :最大值
数据收集函数(去重):collect_set(col)
数据收集函数(不去重):collect_list(col)
##### UDTF表生成函数 - UDTF 表生成函数,T所代表的单词是Table-Generating表生成的意思 - 特点是一进多出,也就是输入一行输出多行。 - 这类型的函数作用返回的结果类似于表,同时,UDTF函数也是我们接触比较少得函数。 - 比如explode函数。 ##### 案例:开发Hive UDF实现手机号****加密 在企业中处理数据的时候,对于敏感数据往往需要进行脱敏处理,比如手机号。我们常见的处理方式是将手机号中间4位进行****处理。 Hive中没有这样的函数可以直接实现功能,虽然可以通过各种函数嵌套调用最终也能实现,但是效率不高,现要求自定义开发实现Hive函数,满足上述需求。 1、能够对输入数据进行非空判断,手机号位数判断 2、能够实现校验手机号格式,把满足规则的进行****处理 3、对于不符合手机号规则的数据直接返回,不处理。 UDF实训啊步骤 - 写一个java类,基层UDF,并重载eveluate方法,方法中实现函数的业务逻辑; - 重载意味着可以在一个java类中实现多个函数功能; - 程序达成jar包,上传HS2服务器本地或者HDFS; - 客户端命令行中添加jar包到Hive的classpath: hive>add jar /xxxx/udf.jar; - 注册成为临时函数(给UDF命名):create temporary function 函数名 as 'UDF类全路径'; - HQL中使用函数 ##### 开发环境准备 - IDEA中创建Maven工程,添加下述pom依赖,用于开发Hive UDF; - 完整pom.xml请参考课程附件资料 ```xml