大数据基础---Hive(第一篇)

数据仓库—Hive

文章目录

  • 数据仓库---Hive
    • 一:Hive的基本概念:
      • 1.1:Hive简介
        • 1.1.1:什么是Hive
        • 1.1.2:为什么要使用Hive呢
        • 1.1.3:Hive的特点
      • 1.2:Hive的架构:
        • 1.2.1:Hive的基本组成
        • 1.2.2:Hive的元数据
        • 1.2.3:HQL的执行流程
      • 1.3:Hive的安装:
        • 1.3.1:Hive的安装方式:
        • 1.3.2:Hive的安装步骤:
    • 二:Hive的数据类型:
      • 2.1:基本数据类型
      • 2.2:Hive中的隐式是数据转换
      • 2.3:复杂类型
    • 三:Hive的内容格式&Hive的存储格式
      • 3.1:Hive的内容格式
      • 3.2:Hive支持的存储格式
      • 3.3:指定存储格式
    • 四:数据库和数据库表的相关操作:
      • 4.1:数据库的相关操作
        • 4.1.1:创建数据库:
        • 4.1.2:查看数据库详细信息
        • 4.1.3:删除数据库
      • 4.2:数据表的相关操作
        • 4.2.1:创建数据库表的语法:
      • 4.3:内部表和外部表
        • 4.3.1:内部表的相关操作:
          • 4.3.1.1:创建一个内部表(没有被external修饰的表就是内部表)
          • 4.3.1.2:创建表并指定字段之间的分隔符
          • 4.3.1.3:根据查询结果创建表
          • 4.3.1.4:根据已经存在的表结构创建表
          • 4.3.1.5:查看表的类型
          • 4.3.1.6:删除表
        • 4.3.2:外部表的相关操作:
          • 4.3.2.1:数据装载命令load
          • 4.3.2.2:操作案例
        • 4.3.3:内部表和外部表之间的转换
          • 4.3.3.1:使用desc命令查看表的类型:
          • 4.3.3.2:修改内部表student为外部表
          • 4.3.3.3:再次查看表的类型:
          • 4.3.3.4:修改外部表student为内部表
          • 4.3.3.5:查询表的类型:
      • 4.4:分区表和分桶表
        • 4.4.1:分区表
          • 4.4.1.1:分区表简介:
          • 4.4.1.2:分区表的应用场景:
          • 4.4.1.3:分区表的相关操作:
          • 4.4.1.3:外部分区表综合练习
        • 4.4.2:分桶表
          • 4.4.2.1:分桶表简介
          • 4.4.2.2:理解分桶表
          • 4.4.2.3:创建分桶表
        • 4.4.3:分区表和分桶表结合使用
      • 4.5:复杂类型的操作
        • 4.5.1. Array类型
        • 4.5.2:map类型
        • 4.5.3:struct类型
      • 4.6:倾斜表
      • 4.7:临时表
      • 4.8:修改表
        • 4.8.1: 表重命名
        • 4.8.2:增加/修改列信息
      • 4.9:删除表
      • 4.10:清空表数据
    • 五:Hive数据查询详解
      • 5.1:select语句:
        • 5.1.1:基本语法:
        • 5.1.2. 全表查询
        • 5.1.3. 选择特定列查询
        • 5.1.4. 列别名
        • 5.1.5. 常用函数
        • 5.1.6. LIMIT语句
        • 5.1.7. WHERE语句
      • 5.2: 运算符
        • 5.2.1:比较运算符:
          • 5.2.1.1:操作符:
          • 5.2.1.2:案例实操
          • 5.2.1.3:LIKE和RLIKE
          • 5.2.1.4:案例实操
        • 5.2.2: 逻辑运算符
      • 5.3. 分组
        • 5.3.1.1. GROUP BY语句
        • 5.3.1.2. HAVING语句
      • 5.4. JOIN语句
        • 5.4.1. 右外连接(RIGHT OUTER JOIN)
        • 5.4.2. 内连接(INNER JOIN)
        • 5.4.3. 左外连接(LEFT OUTER JOIN)
        • 5.4.4. 满外连接(FULL OUTER JOIN)
        • 5.4.5. 多表连接
      • 5.5. 排序
        • 5.5.1. Order By-全局排序
        • 5.5.2. Sort By-每个MapReduce内部局部排序
        • 5.5.3. Distribute By-分区排序
        • 5.5.4. Cluster By
    • **---未完,待续---**

大数据基础---Hive(第一篇)_第1张图片

一:Hive的基本概念:

1.1:Hive简介

The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL. Structure can be projected onto data already in storage. A command line tool and JDBC driver are provided to connect users to Hive.

1.1.1:什么是Hive

Hive是一个构建在Hadoop上的数据仓库框架。最初,Hive是由Facebook开发,后来移交由Apache软件基金会开发,并作为一个Apache开源项目。

Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。

其本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据的存储,说白了hive可以理解为一个将SQL转换为MapReduce的任务的工具,甚至更进一步可以说hive就是一个MapReduce的客户端。

大数据基础---Hive(第一篇)_第2张图片

1.1.2:为什么要使用Hive呢

直接使用hadoop所面临的问题

1、人员学习成本太高

2、项目周期要求太短

3、MapReduce实现复杂查询逻辑开发难度太大

为什么要使用Hive

1、操作接口采用类SQL语法,提供快速开发的能力

2、避免了去写MapReduce,减少开发人员的学习成本

3、功能扩展很方便

1.1.3:Hive的特点

1、Hive最大的特点是通过类SQL来分析大数据,而避免了写MapReduce程序来分析数据,这样使得分析数据更容易。

2、数据是存储在HDFS上的,Hive本身并不提供数据的存储功能,它可以使已经存储的数据结构化。

3、Hive是将数据映射成数据库和一张张的表,库和表的元数据信息一般存在关系型数据库上(比如MySQL)。

4、数据存储方面:它能够存储很大的数据集,可以直接访问存储在Apache HDFS或其他数据存储系统(如Apache HBase)中的文件。

5、数据处理方面:因为Hive语句最终会生成MapReduce任务去计算,所以不适用于实时计算的场景,它适用于离线分析。

6、Hive除了支持MapReduce计算引擎,还支持Spark和Tez这两种分布式计算引擎;

7、数据的存储格式有多种,比如数据源是二进制格式,普通文本格式等等;

1.2:Hive的架构:

大数据基础---Hive(第一篇)_第3张图片

1.2.1:Hive的基本组成

**客户端:**Client CLI(hive shell 命令行),JDBC/ODBC(java访问hive),WEBUI(浏览器访问hive)

**元数据:**Metastore:元数据包括:表名,表所属数据库(默认是default) ,表的拥有者,列/分区字段,表的类型(是否是外部表),表的数据所在目录等

默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore

驱动器:Driver

(1)解析器(SQL Parser):将SQL字符转换成抽象语法树AST,这一步一般使用都是第三方工具库完成,比如antlr,对AST进行语法分析,比如表是否存在,字段是否存在,SQL语句是否有误

(2)编译器(Physical Plan):将AST编译生成逻辑执行计划

(3)优化器(Query Optimizer):对逻辑执行计划进行优化

(4)执行器(Execution):把逻辑执行计划转换成可以运行的物理计划,对于Hive来说,就是MR/Spark

**存储和执行:**Hive使用HDFS进行存储,使用MapReduce进行计算

1.2.2:Hive的元数据

**元数据(metadata):**本质上只是用来存储hive中有哪些数据库,哪些表,表的字段,分区,索引以及命名空间等元信息。元数据存储在关系型数据库中。如hive内置的Derby、第三方数据库如MySQL等。

元数据服务(metastore),作用是:客户端连接metastore服务,metastore再去连接MySQL数据库来存取元数据。有了metastore服务,就可以有多个客户端同时连接,而且这些客户端不需要知道MySQL数据库的用户名和密码,只需要连接metastore 服务即可。

1.2.3:HQL的执行流程

Hive 在执行一条 HQL 的时候,会经过以下步骤:

  1. 语法解析:Antlr 定义 SQL 的语法规则,完成 SQL 词法,语法解析,将 SQL 转化为抽象 语法树 AST Tree;
  2. 语义解析:遍历 AST Tree,抽象出查询的基本组成单元 QueryBlock;
  3. 生成逻辑执行计划:遍历 QueryBlock,翻译为执行操作树 OperatorTree;
  4. 优化逻辑执行计划:逻辑层优化器进行 OperatorTree 变换,合并不必要的 ReduceSinkOperator,减少 shuffle 数据量;
  5. 生成物理执行计划:遍历 OperatorTree,翻译为 MapReduce 任务;
  6. 优化物理执行计划:物理层优化器进行 MapReduce 任务的变换,生成最终的执行计划。

关于 Hive SQL 的详细执行流程可以参考美团技术团队的文章:Hive SQL 的编译过程

1.3:Hive的安装:

1.3.1:Hive的安装方式:

Hive有三种安装方式:分别是内嵌模式、本地模式、远程模式

内嵌模式使用的是内嵌的Derby数据库来存储元数据,也不需要额外起Metastore服务。数据库和Metastore服务都嵌入在主Hive Server进程中。这个是默认的,配置简单,但是一次只能一个客户端连接,适用于用来实验,不适用于生产环境。

解压hive安装包 bin/hive 启动即可使用

缺点:不同路径启动hive,每一个hive拥有一套自己的元数据,无法共享

大数据基础---Hive(第一篇)_第4张图片

本地模式采用外部数据库来存储元数据,目前支持的数据库有:MySQL、Postgres、Oracle、MS SQL Server.在这里我们使用MySQL。

本地模式不需要单独起metastore服务,用的是跟hive在同一个进程里的metastore服务。也就是说当你启动一个hive 服务,里面默认会帮我们启动一个metastore服务。

hive根据hive.metastore.uris 参数值来判断,如果为空,则为本地模式。

缺点是:每启动一次hive服务,都内置启动了一个metastore。

大数据基础---Hive(第一篇)_第5张图片

远程模式下,需要单独起metastore服务,然后每个客户端都在配置文件里配置连接到该metastore服务。远程模式的metastore服务和hive运行在不同的进程里。

在生产环境中,建议用远程模式来配置Hive Metastore。

在这种情况下,其他依赖hive的软件都可以通过Metastore访问hive。

大数据基础---Hive(第一篇)_第6张图片

远程模式下,需要配置hive.metastore.uris 参数来指定metastore服务运行的机器ip和端口,并且需要单独手动启动metastore服务。

1.3.2:Hive的安装步骤:

Hive的具体安装步骤,交互方式,见下期博客更新。

二:Hive的数据类型:

2.1:基本数据类型

Hive 表中的支持以下基本数据类型:

类型 描述 字面量示例
BOOLEAN true/false TRUE
TINYINT 1字节的有符号整数 -128~127 1Y
SMALLINT 2个字节的有符号整数,-32768~32767 1S
INT 4个字节的带符号整数 1
BIGINT 8字节带符号整数 1L
FLOAT 4字节单精度浮点数1.0
DOUBLE 8字节双精度浮点数 1.0
DEICIMAL 任意精度的带符号小数 1.0
STRING 字符串,变长 “a”,’b’
VARCHAR 变长字符串 “a”,’b’
CHAR 固定长度字符串 “a”,’b’
BINARY 字节数组 无法表示
TIMESTAMP 时间戳,毫秒值精度 122327493795
DATE 日期 ‘2016-03-29’
INTERVAL 时间频率间隔

TIMESTAMP 和 TIMESTAMP WITH LOCAL TIME ZONE 的区别如下:

  • TIMESTAMP WITH LOCAL TIME ZONE:用户提交时间给数据库时,会被转换成数据库所在的时区来保存。查询时则按照查询客户端的不同,转换为查询客户端所在时区的时间。
  • TIMESTAMP :提交什么时间就保存什么时间,查询时也不做任何转换。

2.2:Hive中的隐式是数据转换

大数据基础---Hive(第一篇)_第7张图片

2.3:复杂类型

类型 描述 示例
STRUCT 类似于对象,是字段的集合,字段的类型可以不同,可以使用 名称.字段名 方式进行访问 STRUCT (‘xiaoming’, 12 , ‘2018-12-12’)
MAP 键值对的集合,可以使用 名称[key] 的方式访问对应的值 map(‘a’, 1, ‘b’, 2)
ARRAY 数组是一组具有相同类型和名称的变量的集合,可以使用 名称[index] 访问对应的值 ARRAY(‘a’, ‘b’, ‘c’, ‘d’)

三:Hive的内容格式&Hive的存储格式

3.1:Hive的内容格式

当数据存储在文本文件中,必须按照一定格式区别行和列,如使用逗号作为分隔符的 CSV 文件 (Comma-Separated Values) 或者使用制表符作为分隔值的 TSV 文件 (Tab-Separated Values)。但此时也存在一个缺点,就是正常的文件内容中也可能出现逗号或者制表符。

所以 Hive 默认使用了几个平时很少出现的字符,这些字符一般不会作为内容出现在文件中。Hive 默认的行和列分隔符如下表所示。

分隔符 描述
\n 对于文本文件来说,每行是一条记录,所以可以使用换行符来分割记录
^A (Ctrl+A) 分割字段 (列),在 CREATE TABLE 语句中也可以使用八进制编码 \001 来表示
^B 用于分割 ARRAY 或者 STRUCT 中的元素,或者用于 MAP 中键值对之间的分割,
在 CREATE TABLE 语句中也可以使用八进制编码 \002 表示
^C 用于 MAP 中键和值之间的分割,在 CREATE TABLE 语句中也可以使用八进制编码 \003 表示

使用示例如下:

CREATE TABLE page_view(viewTime INT, userid BIGINT)
 ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\001'
   COLLECTION ITEMS TERMINATED BY '\002'
   MAP KEYS TERMINATED BY '\003'
 STORED AS SEQUENCEFILE;

3.2:Hive支持的存储格式

Hive 会在 HDFS 为每个数据库上创建一个目录,数据库中的表是该目录的子目录,表中的数据会以文件的形式存储在对应的表目录下。Hive 支持以下几种文件存储格式:

格式 说明
TextFile 存储为纯文本文件。 这是 Hive 默认的文件存储格式。这种存储方式数据不做压缩,磁盘开销大,数据解析开销大。
SequenceFile SequenceFile 是 Hadoop API 提供的一种二进制文件,它将数据以的形式序列化到文件中。这种二进制文件内部使用 Hadoop 的标准的 Writable 接口实现序列化和反序列化。它与 Hadoop API 中的 MapFile 是互相兼容的。Hive 中的 SequenceFile 继承自 Hadoop API 的 SequenceFile,不过它的 key 为空,使用 value 存放实际的值,这样是为了避免 MR 在运行 map 阶段进行额外的排序操作。
RCFile RCFile 文件格式是 FaceBook 开源的一种 Hive 的文件存储格式,首先将表分为几个行组,对每个行组内的数据按列存储,每一列的数据都是分开存储。
ORC Files ORC 是在一定程度上扩展了 RCFile,是对 RCFile 的优化。
Avro Files Avro 是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro 提供的机制使动态语言可以方便地处理 Avro 数据。
Parquet Parquet 是基于 Dremel 的数据模型和算法实现的,面向分析型业务的列式存储格式。它通过按列进行高效压缩和特殊的编码技术,从而在降低存储空间的同时提高了 IO 效率。

以上压缩格式中 ORC 和 Parquet 的综合性能突出,使用较为广泛,推荐使用这两种格式。

3.3:指定存储格式

通常在创建表的时候使用 STORED AS 参数指定:

CREATE TABLE page_view(viewTime INT, userid BIGINT)
 ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\001'
   COLLECTION ITEMS TERMINATED BY '\002'
   MAP KEYS TERMINATED BY '\003'
 STORED AS SEQUENCEFILE;

各个存储文件类型指定方式如下:

  • STORED AS TEXTFILE
  • STORED AS SEQUENCEFILE
  • STORED AS ORC
  • STORED AS PARQUET
  • STORED AS AVRO
  • STORED AS RCFILE

四:数据库和数据库表的相关操作:

4.1:数据库的相关操作

4.1.1:创建数据库:
create database if not exists `数据库名`;

说明:hive的表存放位置模式是由hive-site.xml当中的一个属性指定的

<name>hive.metastore.warehouse.dirname>
<value>/user/hive/warehousevalue>

创建数据库并指定hdfs存储位置

create database  if not exists`表名` localtion 'hdfs路径'; 
-- 例如:创建数据库myhive到hdfs的'/myhive2目录下:
create database if not exists `myhive` localtion '/myhive2'
4.1.2:查看数据库详细信息
desc databse `数据库名`;
-- 例如:查看数据库myhive的详细信息
desc database myhive;

大数据基础---Hive(第一篇)_第8张图片

4.1.3:删除数据库

删除一个空的数据库,如果数据库下边还有数据表,那么就会报错

drop database `数据库名`;

强制删除一个数据库,包含数据库下面的表一起删除

drop database `数据库名` cascade;

4.2:数据表的相关操作

4.2.1:创建数据库表的语法:
CREATE [EXTERNAL] TABLE [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_format] 
   [STORED AS file_format] 
   [LOCATION hdfs_path]

说明:

1、CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。

2、EXTERNAL关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。

3、LIKE允许用户复制现有的表结构,但是不复制数据。

4、ROW FORMAT DELIMITED 可用来指定行分隔符

5、STORED AS SEQUENCEFILE|TEXTFILE|RCFILE 来指定该表数据的存储格式,hive中,表的默认存储格式为TextFile。

6、CLUSTERED BY对于每一个表(table)进行分桶(MapReuce中的分区),桶是更为细粒度的数据范围划分。Hive也是针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。

把表(或者分区)组织成桶(Bucket)有两个理由:

(1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。

(2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。

7、LOCATION: 指定表在HDFS上的存储位置。

4.3:内部表和外部表

内部表又叫做管理表 (Managed/Internal Table),创建表时不做任何指定,默认创建的就是内部表。想要创建外部表 (External Table),则需要使用 External 进行修饰。 内部表和外部表主要区别如下:

内部表 外部表
数据存储位置 内部表数据存储的位置由 hive.metastore.warehouse.dir 参数指定,默认情况下表的数据存储在 HDFS 的 /user/hive/warehouse/数据库名.db/表名/ 目录下 外部表数据的存储位置创建表时由 Location 参数指定;
导入数据 在导入数据到内部表,内部表将数据移动到自己的数据仓库目录下,数据的生命周期由 Hive 来进行管理 外部表不会将数据移动到自己的数据仓库目录下,只是在元数据中存储了数据的位置
删除表 删除元数据(metadata)和文件 只删除元数据(metadata)
4.3.1:内部表的相关操作:
4.3.1.1:创建一个内部表(没有被external修饰的表就是内部表)
-- 创建一个数据库myhive
create database `myhive`;
-- 使用myhive数据库
use myhive;
--创建一个stu的内部表
create table stu(id int,name string);
-- 查询这个内部表stu
select * from stu;
4.3.1.2:创建表并指定字段之间的分隔符
create table if not exists stu2(id int,name string)   
row format delimited fields terminated by '\t'  --字段之间使用'\t'进行分隔
stored as textfile       -- 存储格式为textfile
location '/user/stu2';    --  HDFS上的存储路径为'/user/stu2'
4.3.1.3:根据查询结果创建表
create table stu3 as select * from stu2;
4.3.1.4:根据已经存在的表结构创建表
create table stu4 like stu2;
4.3.1.5:查看表的类型
desc formatted stu2;

大数据基础---Hive(第一篇)_第9张图片

4.3.1.6:删除表
drop table stu2;
4.3.2:外部表的相关操作:
4.3.2.1:数据装载命令load

Load命令用于将外部数据加载到Hive表中
语法:

load data [local] inpath '/export/servers/datas/student.txt' overwrite | into table student [partition (partcol1=val1,)];

参数:
1、load data:表示加载数据

2、local:表示从本地加载数据到hive表;否则从HDFS加载数据到hive表

3、inpath:表示加载数据的路径

4、overwrite:表示覆盖表中已有数据,否则表示追加

5、into table:表示加载到哪张表

6、student:表示具体的表

7、partition:表示上传到指定分区

4.3.2.2:操作案例

分别创建老师与学生表外部表,并向表中加载数据

源数据如下:

student.txt

01 赵雷 1990-01-01 男 
02 钱电 1990-12-21 男 
03 孙风 1990-05-20 男 
04 李云 1990-08-06 男 
05 周梅 1991-12-01 女 
06 吴兰 1992-03-01 女 
07 郑竹 1989-07-01 女 
08 王菊 1990-01-20 女 

teacher.txt

01 张三 
02 李四 
03 王五 

1、创建老师表:

create external table teacher (t_id string,t_name string) 
row format delimited fields terminated by '\t';

2、创建学生表:

create external table student (s_id string,s_name string,s_birth string , s_sex string ) row format delimited fields terminated by '\t';

3、从本地文件系统向表中加载数据

load data local inpath '/export/servers/hivedatas/student.txt' into table student;

4、加载数据并覆盖已有数据

load data local inpath '/export/servers/hivedatas/student.txt' overwrite  into table student;

5、从hdfs文件系统向表中加载数据
需要提前将数据上传到hdfs文件系统,其实就是一个移动文件的操作

cd /export/servers/hivedatas
hadoop fs -mkdir -p /hivedatas
hadoop fs -put teacher.txt /hivedatas/
load data inpath '/hivedatas/teacher.txt' into table teacher;

注意,如果删掉student表,hdfs的数据仍然存在,并且重新创建表之后,表中就直接存在数据了,因为我们的student表使用的是外部表,drop table之后,表当中的数据依然保留在hdfs上面了

4.3.3:内部表和外部表之间的转换
4.3.3.1:使用desc命令查看表的类型:
desc formatted student;  
-- 从查到的信息中可以看到如下信息
Table Type:MANAGED_TABLE

image-20220105000116043

4.3.3.2:修改内部表student为外部表
alter table student set tblproperties('EXTERNAL'='TRUE');
4.3.3.3:再次查看表的类型:
desc formatted student;
-- 从查到的信息中可以看到如下信息(strudent就变成了外部表)
Table Type:EXTERNAL_TABLE
4.3.3.4:修改外部表student为内部表
alter table student set tblproperties('EXTERNAL'='FALSE');
4.3.3.5:查询表的类型:
desc formatted student;  
-- 从查到的信息中可以看到如下信息
Table Type:MANAGED_TABLE

注意:(‘EXTERNAL’=‘TRUE’)和(‘EXTERNAL’=‘FALSE’)为固定写法,区分大小写!

4.4:分区表和分桶表

4.4.1:分区表
4.4.1.1:分区表简介:

在大数据中,最常用的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,这样每次操作一个小的文件就会很容易了,同样的道理,在hive当中也是支持这种思想的,就是我们可以把大的数据,按照每天,或者每小时进行切分成一个个的小的文件,这样去操作小的文件就会容易得多了。

Hive 中的表对应为 HDFS 上的指定目录,在查询数据时候,默认会对全表进行扫描,这样时间和性能的消耗都非常大。

分区为 HDFS 上表目录的子目录,数据按照分区存储在子目录中。如果查询的 where 字句的中包含分区条件,则直接从该分区去查找,而不是扫描整个表目录,合理的分区设计可以极大提高查询速度和性能。

这里说明一下分区表并 Hive 独有的概念,实际上这个概念非常常见。比如在我们常用的 Oracle 数据库中,当表中的数据量不断增大,查询数据的速度就会下降,这时也可以对表进行分区。表进行分区后,逻辑上表仍然是一张完整的表,只是将表中的数据存放到多个表空间(物理文件上),这样查询数据时,就不必要每次都扫描整张表,从而提升查询性能。

4.4.1.2:分区表的应用场景:

通常,在管理大规模数据集的时候都需要进行分区,比如将日志文件按天进行分区,从而保证数据细粒度的划分,使得查询性能得到提升。

4.4.1.3:分区表的相关操作:

创建分区表语法

create table score(s_id string,c_id string, s_score int)
partitioned by (month string) 
row format delimited fields terminated by '\t';

创建一个表带多个分区

create table score2 (s_id string,c_id string, s_score int)
partitioned by (year string,month string,day string)
row format delimited fields terminated by '\t';

加载数据到分区表中

load data local inpath '/export/servers/hivedatas/score.txt' into table score partition (month='202006');

加载数据到一个多分区的表中去

load data local inpath '/export/servers/hivedatas/score.txt' into table score2 partition(year='2020',month='06',day='01');

查看分区

show partitions score;

添加一个分区

alter table score add partition(month='202005');

同时添加多个分区

alter table score add partition(month='202004') partition(month = '202003');

注意:添加分区之后就可以在hdfs文件系统当中看到表下面多了一个文件夹

删除分区

alter table score drop partition(month = '202006');
4.4.1.3:外部分区表综合练习

需求描述:现在有一个文件score.txt文件,存放在集群的这个目录下/scoredatas/month=202006,这个文件每天都会生成,存放到对应的日期文件夹下面去,文件别人也需要公用,不能移动。需求,创建hive对应的表,并将数据加载到表中,进行数据统计分析,且删除表之后,数据不能删除。

1、数据准备:

hadoop fs -mkdir -p /scoredatas/month=202006
hadoop fs -put score.txt/scoredatas/month=202006/

2、创建外部分区表,并指定文件数据存放目录

create external table score4(s_id string, c_id string,s_score int)
partitioned by (month string) 
row format delimited fields terminated by '\t' 
location '/scoredatas';

2、进行表的修复,说白了就是建立我们表与我们数据文件之间的一个关系映射

msck repair table score4;

修复成功之后即可看到数据已经全部加载到表当中去了

第二种实现方式,上传数据之后手动添加分区即可
数据准备:

hadoop fs -mkdir -p /scoredatas/month=202005
hadoop fs -put score.txt/scoredatas/month=202005

修改表,进行手动添加方式

alter table score4 add partition(month='202005');
4.4.2:分桶表
4.4.2.1:分桶表简介

分区提供了一个隔离数据和优化查询的可行方案,但是并非所有的数据集都可以形成合理的分区,分区的数量也不是越多越好,过多的分区条件可能会导致很多分区上没有数据。同时 Hive 会限制动态分区可以创建的最大分区数,用来避免过多分区文件对文件系统产生负担。鉴于以上原因,Hive 还提供了一种更加细粒度的数据拆分方案:分桶表 (bucket Table)。

分桶表会将指定列的值进行哈希散列,并对 bucket(桶数量)取余,然后存储到对应的 bucket(桶)中。

4.4.2.2:理解分桶表

单从概念上理解分桶表可能会比较晦涩,其实和分区一样,分桶这个概念同样不是 Hive 独有的,对于 Java 开发人员而言,这可能是一个每天都会用到的概念,因为 Hive 中的分桶概念和 Java 数据结构中的 HashMap 的分桶概念是一致的。

当调用 HashMap 的 put() 方法存储数据时,程序会先对 key 值调用 hashCode() 方法计算出 hashcode,然后对数组长度取模计算出 index,最后将数据存储在数组 index 位置的链表上,链表达到一定阈值后会转换为红黑树 (JDK1.8+)。下图为 HashMap 的数据结构图:

大数据基础---Hive(第一篇)_第10张图片

4.4.2.3:创建分桶表

在 Hive 中,我们可以通过 CLUSTERED BY 指定分桶列,并通过 SORTED BY 指定桶中数据的排序参考列。

开启hive的桶表功能

set hive.enforce.bucketing=true;

设置reduce的个数

set mapreduce.job.reduces=3;  

创建通表

create table course (c_id string,c_name string,t_id string) 
clustered by(c_id) into 3 buckets   -- 分桶字段为c_id,按照分桶字段分三个桶
row format delimited fields terminated by '\t';

桶表的数据加载,由于桶表的数据加载通过hdfs dfs -put文件或者通过load data均不好使,只能通过insert overwrite

创建普通表,并通过insert overwrite的方式将普通表的数据通过查询的方式加载到桶表当中去

创建普通表:

create table course_common (c_id string,c_name string,t_id string) 
row format delimited fields terminated by '\t';

普通表中加载数据

load data local inpath '/export/servers/hivedatas/course.txt' into table course_common;

通过insert overwrite给桶表中加载数据

insert overwrite table course select * from course_common cluster by(c_id);
4.4.3:分区表和分桶表结合使用

分区表和分桶表的本质都是将数据按照不同粒度进行拆分,从而使得在查询时候不必扫描全表,只需要扫描对应的分区或分桶,从而提升查询效率。两者可以结合起来使用,从而保证表数据在不同粒度上都能得到合理的拆分。下面是 Hive 官方给出的示例:

CREATE TABLE page_view_bucketed(
	viewTime INT, 
    userid BIGINT,
    page_url STRING, 
    referrer_url STRING,
    ip STRING )
 PARTITIONED BY(dt STRING)
 CLUSTERED BY(userid) SORTED BY(viewTime) INTO 32 BUCKETS
 ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\001'
   COLLECTION ITEMS TERMINATED BY '\002'
   MAP KEYS TERMINATED BY '\003'
 STORED AS SEQUENCEFILE;

此时导入数据时需要指定分区:

INSERT OVERWRITE page_view_bucketed
PARTITION (dt='2009-02-25')
SELECT * FROM page_view WHERE dt='2009-02-25';

4.5:复杂类型的操作

4.5.1. Array类型

源数据:
说明:name与locations之间制表符分隔,locations中元素之间逗号分隔

zhangsan	  beijing,shanghai,tianjin,hangzhou
wangwu   	changchun,chengdu,wuhan,beijin

建表语句

create table hive_array(name string, work_locations array<string>)
row format delimited fields terminated by '\t'
COLLECTION ITEMS TERMINATED BY ',';

导入数据(从本地导入,同样支持从HDFS导入)

load data local inpath '/export/servers/hivedatas/work_locations.txt' overwrite into table hive_array;

常用查询:

-- 查询所有数据
select * from hive_array;
-- 查询loction数组中第一个元素
select name, work_locations[0] location from hive_array;
-- 查询location数组中元素的个数
select name, size(work_locations) location from hive_array;
-- 查询location数组中包含tianjin的信息
select * from hive_array where array_contains(work_locations,'tianjin'); 
4.5.2:map类型

源数据:
说明:字段与字段分隔符: “,”;需要map字段之间的分隔符:"#";map内部k-v分隔符:":"

1,zhangsan,father:xiaoming#mother:xiaohuang#brother:xiaoxu,28
2,lisi,father:mayun#mother:huangyi#brother:guanyu,22
3,wangwu,father:wangjianlin#mother:ruhua#sister:jingtian,29
4,mayun,father:mayongzhen#mother:angelababy,26

建表语句

create table hive_map(
id int, name string, members map<string,string>, age int
)
row format delimited
fields terminated by ','
COLLECTION ITEMS TERMINATED BY '#' 
MAP KEYS TERMINATED BY ':'; 

导入数据

load data local inpath '/export/servers/hivedatas/hive_map.txt' overwrite into table hive_map;

常用查询

select * from hive_map;
select id, name, members['father'] father, members['mother'] mother, age from hive_map;
select id, name, map_keys(members) as relation from hive_map;
select id, name, map_values(members) as relation from hive_map;
select id,name,size(members) num from hive_map;
select * from hive_map where array_contains(map_keys(members), 'brother');
select id,name, members['brother'] brother from hive_map where array_contains(map_keys(members), 'brother');
4.5.3:struct类型

源数据:
说明:字段之间#分割,第二个字段之间冒号分割

192.168.1.1#zhangsan:40
192.168.1.2#lisi:50
192.168.1.3#wangwu:60
192.168.1.4#zhaoliu:70

建表语句

create table hive_struct(
ip string, info struct<name:string, age:int>
)
row format delimited
fields terminated by '#'
COLLECTION ITEMS TERMINATED BY ':';

导入数据

load data local inpath '/export/servers/hivedatas/hive_struct.txt' into table hive_struct;

常用查询

select * from hive_struct;
select ip, info.name from hive_struct;

4.6:倾斜表

通过指定一个或者多个列经常出现的值(严重偏斜),Hive 会自动将涉及到这些值的数据拆分为单独的文件。在查询时,如果涉及到倾斜值,它就直接从独立文件中获取数据,而不是扫描所有文件,这使得性能得到提升。

  CREATE EXTERNAL TABLE emp_skewed(
    empno INT,
    ename STRING,
    job STRING,
    mgr INT,
    hiredate TIMESTAMP,
    sal DECIMAL(7,2),
    comm DECIMAL(7,2)
    )
    SKEWED BY (empno) ON (66,88,100)  --指定 empno 的倾斜值 66,88,100
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    LOCATION '/hive/emp_skewed';   

4.7:临时表

临时表仅对当前 session 可见,临时表的数据将存储在用户的暂存目录中,并在会话结束后删除。如果临时表与永久表表名相同,则对该表名的任何引用都将解析为临时表,而不是永久表。临时表还具有以下两个限制:

  • 不支持分区列;
  • 不支持创建索引。
  CREATE TEMPORARY TABLE emp_temp(
    empno INT,
    ename STRING,
    job STRING,
    mgr INT,
    hiredate TIMESTAMP,
    sal DECIMAL(7,2),
    comm DECIMAL(7,2)
    )
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";

4.8:修改表

4.8.1: 表重命名

​ 基本语法:

alter table old_table_name rename to new_table_name;

– 把表score4修改成score5

alter table score4 rename to score5;
4.8.2:增加/修改列信息

– 1:查询表结构

desc score5;

– 2:添加列

alter table score5 add columns (mycol string, mysco string);

– 3:查询表结构

desc score5;

– 4:更新列

alter table score5 change column mysco mysconew int;

– 5:查询表结构

desc score5;

4.9:删除表

drop table score5;

4.10:清空表数据

只能清空管理表,也就是内部表

truncate table score6;

五:Hive数据查询详解

5.1:select语句:

5.1.1:基本语法:
SELECT [ALL | DISTINCT]select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BYcol_list]
[HAVING where_condition]
[ORDER BYcol_list]
[CLUSTER BYcol_list
  | [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]

解释:

1、ORDER BY用于全局排序,就是对指定的所有排序键进行全局排序,使用ORDER BY的查询语句,最后会用一个Reduce Task来完成全局排序。

2、sort by用于分区内排序,即每个Reduce任务内排序**。**,则sort by只保证每个reducer的输出有序,不保证全局有序。

3、**distribute by(**字段)根据指定的字段将数据分到不同的reducer,且分发算法是hash散列。

4、**cluster by(**字段) 除了具有Distribute by的功能外,还兼具sort by的排序功能。

因此,如果分桶和sort字段是同一个时,此时,cluster by = distribute by + sort by。

5.1.2. 全表查询
select * from score;
5.1.3. 选择特定列查询
select s_id ,c_id from score;
5.1.4. 列别名
select s_id as myid ,c_id from score;
5.1.5. 常用函数

1)求总行数(count)

 select count(1) from score;

2)求分数的最大值(max)

 select max(s_score) from score;

3)求分数的最小值(min)

 select min(s_score) from score;

4)求分数的总和(sum)

 select sum(s_score) from score;

5)求分数的平均值(avg)

 select avg(s_score) from score;
5.1.6. LIMIT语句

典型的查询会返回多行数据。LIMIT子句用于限制返回的行数。

select * from score limit 3;
5.1.7. WHERE语句

1)使用WHERE 子句,将不满足条件的行过滤掉。

2)WHERE 子句紧随 FROM 子句。

3)案例实操

查询出分数大于60的数据

select * from score where s_score > 60;

5.2: 运算符

5.2.1:比较运算符:
5.2.1.1:操作符:
操作符 支持的数据类型 描述
A=B 基本数据类型 如果A等于B则返回TRUE,反之返回FALSE
A<=>B 基本数据类型 如果A和B都为NULL,则返回TRUE,其他的和等号(=)操作符的结果一致,如果任一为NULL则结果为NULL
A<>B, A!=B 基本数据类型 A或者B为NULL则返回NULL;如果A不等于B,则返回TRUE,反之返回FALSE
A 基本数据类型 A或者B为NULL,则返回NULL;如果A小于B,则返回TRUE,反之返回FALSE
A<=B 基本数据类型 A或者B为NULL,则返回NULL;如果A小于等于B,则返回TRUE,反之返回FALSE
A>B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于B,则返回TRUE,反之返回FALSE
A>=B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于等于B,则返回TRUE,反之返回FALSE
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
IN(数值1, 数值2) 所有数据类型 使用 IN运算显示列表中的值
A [NOT] LIKE B STRING 类型 B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回TRUE;反之返回FALSE。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。
A RLIKE B, A REGEXP B STRING 类型 B是一个正则表达式,如果A与其匹配,则返回TRUE;反之返回FALSE。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。
5.2.1.2:案例实操
-- (1)查询分数等于80的所有的数据
select * from score where s_score = 80;
-- (2)查询分数在80到100的所有数据
select * from score where s_score between 80 and 100;
-- (3)查询成绩为空的所有数据
select * from score where s_score is null;
-- (4)查询成绩是80和90的数据
select * from score where s_score in(80,90);
5.2.1.3:LIKE和RLIKE

1)使用LIKE运算选择类似的值

2)选择条件可以包含字符或数字:

% 代表零个或多个字符(任意个字符)。

_ 代表一个字符。

3)RLIKE子句是Hive中这个功能的一个扩展,其可以通过Java的正则表达式这个更强大的语言来指定匹配条件。

5.2.1.4:案例实操
-- (1)查找以8开头的所有成绩
select * from score where s_score like '8%';
-- (2)查找第二个数值为9的所有成绩数据
select * from score where s_score like '_9%';
-- (3)查找成绩中含9的所有成绩数据
select * from score where s_score rlike '[9]';		
5.2.2: 逻辑运算符
操作符 含义
AND 逻辑并
OR 逻辑或
NOT 逻辑否

案例实操
(1)查询成绩大于80,并且s_id是01的数据

select * from score where s_score >80 and s_id = '01';

(2)查询成绩大于80,或者s_id 是01的数

select * from score where s_score > 80 or s_id = '01';

(3)查询s_id 不是 01和02的学生

select * from score where s_id not in ('01','02');

5.3. 分组

5.3.1.1. GROUP BY语句

GROUP BY语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。注意使用group by分组之后,select后面的字段只能是分组字段和聚合函数。

案例实操:
(1)计算每个学生的平均分数

select s_id ,avg(s_score) from score group by s_id;

(2)计算每个学生最高成绩

select s_id ,max(s_score) from score group by s_id;
5.3.1.2. HAVING语句

1、having与where不同点
(1)where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。
(2)where后面不能写分组函数,而having后面可以使用分组函数。
(3)having只用于group by分组统计语句。
2、案例实操:
– 求每个学生的平均分数

select s_id ,avg(s_score) from score group by s_id;

– 求每个学生平均分数大于85的人

select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85;

5.4. JOIN语句

5.4.1. 右外连接(RIGHT OUTER JOIN)

右外连接:JOIN操作符右边表中符合WHERE子句的所有记录将会被返回。

select * from teacher t right join course c on t.t_id = c.t_id;
5.4.2. 内连接(INNER JOIN)

内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。

select * from teacher t inner join course c on t.t_id = c.t_id;
5.4.3. 左外连接(LEFT OUTER JOIN)

​ 左外连接:JOIN操作符左边表中符合WHERE子句的所有记录将会被返回。
查询老师对应的课程

select * from teacher t left join course c on t.t_id = c.t_id;
5.4.4. 满外连接(FULL OUTER JOIN)

​ 满外连接:将会返回所有表中符合WHERE语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用NULL值替代。

SELECT * FROM teacher t FULL JOIN course c ON t.t_id = c.t_id ;
5.4.5. 多表连接

注意:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生

select * from teacher t 
left join course c 
on t.t_id = c.t_id
left join score s 
on s.c_id = c.c_id
left join student stu 
on s.s_id = stu.s_id;

大多数情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表teacher和表course进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表score;进行连接操作。

5.5. 排序

5.5.1. Order By-全局排序

Order By:全局排序,一个reduce

1、使用 ORDER BY 子句排序
ASC(ascend): 升序(默认)
DESC(descend): 降序
2、ORDER BY 子句在SELECT语句的结尾。
3、案例实操
(1)查询学生的成绩,并按照分数降序排列

SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;

(2)按照分数的平均值排序

select s_id ,avg(s_score) avg from score group by s_id order by avg;

(3)按照学生id和平均成绩进行排序

select s_id ,avg(s_score) avg from score group by s_id order by s_id,avg;
5.5.2. Sort By-每个MapReduce内部局部排序

Sort By:每个MapReduce内部进行排序,对全局结果集来说不是排序。

1)设置reduce个数

 set mapreduce.job.reduces=3;

2)查看设置reduce个数

 set mapreduce.job.reduces;

3)查询成绩按照成绩降序排列

 select * from score sort by s_score;

4)将查询结果导入到文件中(按照成绩降序排列)

insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;
5.5.3. Distribute By-分区排序

Distribute By:类似MR中partition,进行分区,结合sort by使用。

注意,Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。

对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。

案例实操:

先按照学生id进行分区,再按照学生成绩进行排序。

1)设置reduce的个数,将我们对应的s_id划分到对应的reduce当中去

set mapreduce.job.reduces=7;

2)通过distribute by进行数据的分区

insert overwrite local directory '/export/servers/hivedatas/sort' select * from score distribute by s_id sort by s_score;
5.5.4. Cluster By

当distribute by和sort by字段相同时,可以使用cluster by方式。

cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是倒序排序,不能指定排序规则为ASC或者DESC。

以下两种写法等价:

select * from score cluster by s_id; 
select * from score distribute by s_id sort by s_id;

—未完,待续—

你可能感兴趣的:(大数据,hive,数据仓库,big,data)