Hive学习

Hive

Hive是Hadoop的一个数据仓库工具,它可以将结构化的数据文件映射到一张数据表之中持久化在HDFS上,并提供类似于SQL的HQL语言来对数据表进行增、删、改、查等操作。它底层会将HQL语句转化为MapReduce任务进行执行。
作为Hadoop的数据仓库,故其为建立在Hadoop上的数据仓库基础架构,其数据分为两种:元数据和数据,元数据存储在关系型数据库之中,而数据持久化在HDFS上。
此外,Hive不支持OLTP(联机事务处理)。反而更接近成为一个OLAP(联机分析技术)工具,毕竟Hadoop被设计出就是用于处理的数据规模是非常大的,因此提交查询和返回结果是可能具有非常大的延时的。如果用户需要对这些大规模的数据使用OLTP功能的话,那么应当使用一个NOSQL的数据库,例如和Hadoop结合使用的HBase等。
大部分的数据仓库应用程序是基于SQL的关系型数据库实现的,故此降低了这些应用移植到Hadoop上的障碍。故用户只需懂得SQL就可以对Hive进行简单的数据操纵。

Hive的安装

我们知道Hive是基于Hadoop基础上的一种数据仓库,其元数据是通过关系型数据库进行存储的,故其先决条件是Hadoop集群和关系型数据库(这里使用MySQL)
(注意:Hive默认使用derby数据库,由于其只能存在一个连接,我们将其改为MySQL)

  1. 准备安装MySQL的Hadoop集群和Hive的安装的压缩包
  2. 解压安装包
  3. 配置环境变量(将Hive的安装位置加入到环境变量之中)
  4. 修改Hive的配置
    (Hive的配置信息在\({HIVE_HOME}/conf/hive-default.xml.template文件下,如果我们需要对Hive的配置信息做出修改时,我们需要先在\){HIVE_HOME}/conf/目录下创建hive-site.xml文件,然后将要修改的配置信息放在此文件中。)
    • hive-site.xml

      <!--设置mr程序中间产生结果的hdfs临时存储路径-->
      <property>
      	<name>hive.exec.scratchdir</name>
      	<value>/tmp/hive</value>
      </property>
      <property>
      	<name>hive.exec.local.scratchdir</name>
      	<value>/home/hyxy/tmp/hive</value>
      </property>
      <!--设置hive连接数据库使用的用户名-->
      <property>
      	<name>javax.jdo.option.ConnectionUserName</name>
      	<value>hyxyhive1</value><!--用户名-->
      </property>
      <!--设置数据库使用的用户的密码-->
      <property>
      	<name>javax.jdo.option.ConnectionPassword</name>
      	<value>123456</value>
      </property>
      <!--设置hive数据库连接的url-->
      <property>
      	<name>javax.jdo.option.ConnectionURL</name>
      	<value>jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true</value>
      </property>
      <!--设置hive中存储的元数据的关系型数据库,默认为derby数据库-->
      <property>
      	<name>javax.jdo.option.ConnectionDriverName</name>
      	<value>com.mysql.jdbc.Driver</value>
      </property>
      <!--设置hive元数据的默认存储位置-->
      <property>
      	<name>hive.metastore.warehouse.dir</name>
      	<value>/user/hive/warehouse</value>
      </property>
      <!--设置cli显示当前数据库(便于操作)-->
      <property>
      	<name>hive.cli.print.current.db</name>
      	<value>true</value>
      </property>
      <!--设置动态分区的最大分区数,默认1000-->
      <property>
      	<name>hive.exec.max.dynamic.partitions</name>
      	<value>1000000</value>
      </property>
      <!--设置没个节点的动态分区的最大值,默认100-->
      <property>
      	<name>hive.exec.max.dynamic.partitions.pernode</name>
      	<value>1000000</value>
      </property>
      <property>
      	<name>hive.server2.thrift.bind.host</name>
      	<value>master</value>
      </property>
      <!--配置beeline远程客户端连接时的用户名和密码。
                  这个用户名要在对应的hadoop的配置文件core-site.xml中也配>置
      -->
      <!--使用beeline连接hiveserver2所使用的用户名-->
      <property>
      	<name>hive.server2.thrift.client.user</name>
      	<value>hyxy</value>
      </property>
      <!--使用beeline连接hiveserver2所使用的用户的密码-->
      <property>
      	<name>hive.server2.thrift.client.password</name>
      	<value>123456</value>
      </property>
      
    • core-site.xml

      <property>
      	<name>hadoop.proxyuser.hyxy.hosts</name>
      	<value>*</value>
      </property>
      <property>
      	<name>hadoop.proxyuser.hyxy.groups</name>
      	<value>*</value>
      </property>
      
  5. 安装完成

Hive的使用

在Hive的安装目录的bin文件夹下有三个常使用的命令

  • hive
    本地使用hive工具,对hive进行操作
  • hiveserver2
    开启hiveserver2服务后,集群上的其他节点可通过beeline连接此节点的hive(Hive一个客户端)
  • beeline
    使用beeline连接指定的hive客户端

数据类型

Hive的数据类型除了在一般关系型数据库中含有的集中基本数据类型,它还具有一些特有的集合数据类型。

  • 基本数据类型

    数据类型 长度
    TINYINT 1byte有符号整数
    SMALLINT 2byte有符号整数
    INT 4byte有符号整数
    BIGINT 8byte有符号整数
    BOOLEAN 布尔类型,true或false
    FLOAT 单精度浮点数
    DOUBLE 双精度浮点数
    STRING 字符序列。可以指定字符集,可以使用单引号或者双引号
    TIMESTAMP 整数,浮点数或者字符串
    BINARY 字节数组
  • 集合数据类型

    |数据类型 | 描述 |
    |ARRAY | 数组,用来存储具有相同数据类型的变量的集合|
    |MAP | MAP是一组键值对元组集合|
    |STRUCT | 与c语言的结构体相类似,通过点来访问变量值|

Hive操作

Hive的操作是通过HQL语句进行操作,HQL语句与SQL语句有着非常大的相似之处(可简单的看成SQL),HQL在底层实现的时候将其转化为MapReduce程序进行执行。

  1. 对表结构进行操作
    • 建立表结构
      Create table 表名 [if not exists]( 
      字段1 数据类型 comment "描述信息"
      字段2 数据类型 comment "描述信息",
      …
      )
      [partitioned by (字段1 数据类型 [字段n 数据类型])]
      [clustered by(id)into (num) buckets]
      [row format delimited 
      [fields terminated by '分隔符1']
      [collection items terminated by '分隔符']
      [map keys terminated by '分隔符']
      [lines terminated by '分隔符']
      		]
      		[stored as 文件格式(TEXTFILE)]
      		[Location '存储路径'];
      -- 注:
      
    • 修改表结构
      Alter table 表名 +操作
      例如:
      	Alter table table1 rname table2;
      	Alter table table2 add partition(partition_key=值)
      	...
      
  2. 对表数据进行操作
    • 插入数据
      插入数据的方式有三种:

      1. 单个数据插入(与SQL的语法一致)
        Insert into (字段1,字段2,字段n) values(值1,值2,值n)。由于数据单个插入也会运行一个mr程序,故此我们常用数据加载的方式插入数据
      2. 将数据以文件形式上传(移动,拷贝)至HDFS的指定位置
        • Hadoop fs -put 本地文件路径 表所在路径
        • Hadoop fs -mv(-cp) 数据文件所在路径 表所在路径
      3. 将数据以文件形式加载到表中(加载HDFS中的数据文件会将与路径下的文件删除)
        • Load data local inpath '本地路径' [overwrite] into table 表名
        • Load data inpath '本地路径' [overwrite] into table 表名

      注意:后两种需要在创建表的时候指定相应的分隔符,数据文件中的数据的分隔符也要与之相对应,当数据插入到Hive后,我们可以查看到HDFS上表所在路径下会出现所对应的相应的文件,文件名的格式类似为000000-0等编号信息

    • 查询数据
      由于其查询语言与SQL有着过人的相似之处,故其也支持一些类似于UNION,UNION ALL,JOIN,子查询等方式。

重点

读时模式与写时模式

  • 读时模式
    所谓的读时模式就是,Hive不会在数据加载的时候进行对数据的验证,而是在数据查询的时候运行。因而它可以使得数据的加载十分迅速

  • 写时模式
    写时模式恰恰与读时模式相反,Hive会在数据加载的时候对数据进行验证,二在数据加载的时候不问不管。故此其查询效率是是有所提升的

  • 两者的选取
    由于其在对数据进行验证的时候的不同,故两者在不同场景下使用的效率而会受到相对的影响,用户必须在两者之间权衡。

管理表与托管表

  • 管理表
    管理表也叫内部表,我们一般默认创建的表都是管理表,默认的存储位置(仓库目录)由配置项中的 hive.metastore.warehouse.dir 决定,当然,我们也可以自己指定其存储路径。在这种表中,hive会(或多或少)控制着hive中数据的生命周期,当该管理表被删除的时候,其所存储的数据以及元数据都会被删除。因此,管理表不适合与其他的应用一起共享管理数据。

  • 托管表
    托管表也叫外部表,在在创建表的时候通过 EXTERNAL 关键词来指定其为外部表。当指定该表为外部表的时候,Hive 知道该表数据并非由自己管理,也就不会将此表放入到自己的仓库目录下,因此我们在创建外部表的时候必须指定其存储的位置。然而事实上,在外部表定义的时候,Hive 都不会去检查该存储路径的正确性,这就意味着我们可以把创建数据推迟到创建表之后才进行。
    当外部表被删除的时候,Hive是不会删出持久化在HDFS上的数据,它只会将元数据删除

  • 两者的转化
    两者的转化可以通过 ALTER 语句(修改表结构)来进行转化,具体使用如下:

    内部转外部
    alter table tableA set TBLPROPERTIES('EXTERNAL'='true')
    外部转内部
    alter table tableA set TBLPROPERTIES('EXTERNAL'='false')
    
  • 两者的优缺点

    • 大多数情况下两者并没有什么区别(drop语句除外)。
    • 管理表:表被删除时,表中的元数据与持久化在HDFS上的数据都会被删除。适用于数据只由Hive应用管理的场景。
    • 外部表:表被删除时只会删除存在表中的元数据,持久化在HDFS上的数据是不会被删除的。适用于数据由多种应用共同管理的场景

分区与分桶

  • 分区

    1. 为什么会有分区
      Hive是基于大数据基础上的一个数据仓库,其所存储的数据并非小量,而是可能达到TB,PB甚至及以上。而且随着系统运行的时间增长,其数据的增长量也是十分之大的。但是,Hive在扫描数据的时候,一般默认全表扫描,这样会导致大量的不必要的数据扫描,降低了查询的效率。

    2. 怎么分区
      根据业务的不同,选择较为高效的分区方式

    3. 分区的语法:

      PARTITIONED BY(COL_NAME DATA_TYPE)
      

      值得注意的是:

      • Hive分区使用的字段是表外字段,而MySQL使用的是表内字段;
      • Hive的分区名区分大小写;
      • Hive分区的本质是在该表下建立目录,其分区列是伪列,并不真实存在表中;
      • 一张表可以有一个或多个分区,分区下可以嵌套多个分区,以规定分区是的字段顺序进行嵌套。
    4. 分区的意义
      分区的主要目的就是为了减少不必要的数据扫描,减少数据扫描的范围(查询语句通过where指定分区),提高查询的效率。

    5. 创建分区表
      定义表结构的时候指定分区,例如创建分区表 part_table,字段为uid(int),uname(string),根据country(string)和date(string)进行嵌套分区(先对country进行分区,再对date进行分区),每个字段以','间隔。

      create table if not exists part_table(
      uid int,
      uname string
      )
      PARTITIONED BY (country string,date_time string)
      row format delimited 
      fields terminated by ',';
      
    6. 动态分区与静态分区

      • 静态分区
        静态分区是指在将数据插入表中的时候指定其所在的分区。例如:
        insert into part_table(uid,uname) values(18,'zhangsan') partition(country='China',date_time='2016-11-11');
        -- 或者是用数据加载的方式
        load data local inpath '数据文件所在的本地路径' into table part_table partition(country='China',date_time='2016-11-11')
        
      • 动态分区
        所谓的动态分区就是在插入数据的时候不指定其分区,然后根据数据来自己确定分区。(注:此种方式不能使用数据加载的方式进行数据插入),例如:
        -- 从data_table表中选取数据插入到part_table中,
        insert into part_table partition(country,date_time) select * from data_table;
        -- 注,查询的数据必须列数必须与要插入的表的列相吻合。
        
        使用动态分区技术的时候,必须设置 动态分区是不严格的,这个设置可以在hive-site.xml中设置,也可在sql执行时临时设置,使其暂时生效。如果使用动态分区是所要分区数过多,建议修改每个节点的分区数的最大值和分区数的最大值
        hive.exec.dynamic.partition.mode=nonstrict
        
  • 分桶

    1. 什么是分桶
      分区提供了一个隔离数据和优化查询的便利的方式。但是,并非所有的数据集都可以形成合理的分区,尤其是当防止数据倾斜的时候。而分桶是将数据分解管理的另一技术,是对数据进行更细粒度的划分。

    2. 怎么分桶
      Hive 默认是采用对某一列的每个数据进行 hash ,使用 hashcode 对桶的个数进行取余,然后确定该数据应当是放在哪个桶中。

    3. 分桶的语法

      CLUSTERED BY (col_name, col_name, ...) 
      

      注:若分区与分桶同时存在的话,分桶必须在分区之后

    4. 分桶的意义

      1. 由于桶的数量是一定的,所以它没有数据波动。
      2. 有利于高效的执行map-side JOIN。
      3. 分桶的效率一定高于分区。
posted @ 2020-07-03 19:39  哎,疯!  阅读(80)  评论(0编辑  收藏  举报