HIVE体系结构

HIVE体系结构

  • HIVE体系结构
    • Hive架构与基本组成
      • (1)单用户模式
      • (2)多用户模式
      • (3) 远程服务器模式。
    • Hive的数据模型:
      • (1)Hive数据库
      • (2)内部表 
      • (3)外部表
      • (4)分区
      • (5)桶
      • (6)Hive的视图
    • Hive的执行原理
    • Hive和数据库的异同
    • Hive元数据库
       
    • Hive基本操作
    • 使用HIVE注意点
    • Hive的扩展特性
      • (1)数据文件格式
      • (2)SerDe
      • (3)Map/Reduce脚本(Transform)
      • (4)UDF(User-Defined-Function)
      • (5)UDAF(User-Defined Aggregation Funcation)

Hive架构与基本组成

    下面是Hive的架构图。

HIVE体系结构

图1.1 Hive体系结构

    Hive的体系结构可以分为以下几部分:

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

    Hive将元数据存储在RDBMS中,有三种模式可以连接到数据库:

(1)单用户模式

      此模式连接到一个In-memory 的数据库Derby,一般用于Unit Test。

HIVE体系结构

图2.1 单用户模式

(2)多用户模式

       通过网络连接到一个数据库中,是最经常使用到的模式。

HIVE体系结构

图2.2 多用户模式

(3) 远程服务器模式。

       用于非Java客户端访问元数据库,在服务器端启动MetaStoreServer,客户端利用Thrift协议通过MetaStoreServer访问元数据库。

HIVE体系结构

    对于数据存储,Hive没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由的组织Hive中的表,只需要在创建表的时候告诉Hive数据中的列分隔符和行分隔符,Hive就可以解析数据。Hive中所有的数据都存储在HDFS中,存储结构主要包括数据库、文件、表和视图。Hive中包含以下数据模型:Table内部表,External Table外部表,Partition分区,Bucket桶。Hive默认可以直接加载文本文件,还支持sequence file 、RCFile。

Hive的数据模型:

(1)Hive数据库

    类似传统数据库的DataBase,在第三方数据库里实际是一张表。简单示例命令行 hive > create database test_database; 

(2)内部表 

    Hive的内部表与数据库中的Table在概念上是类似。每一个Table在Hive中都有一个相应的目录存储数据。例如一个表pvs,它在HDFS中的路径为/wh/pvs,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir} 指定的数据仓库的目录,所有的Table数据(不包括External Table)都保存在这个目录中。删除表时,元数据与数据都会被删除。

    内部表简单示例:
    创建数据文件:test_inner_table.txt

    创建表:create table test_inner_table (key string)
    加载数据:LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table
    查看数据:select * from test_inner_table;  select count(*) from test_inner_table
    删除表:drop table test_inner_table

(3)外部表

    外部表指向已经在HDFS中存在的数据,可以创建Partition。它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异。内部表的创建过程和数据加载过程这两个过程可以分别独立完成,也可以在同一个语句中完成,在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。而外部表只有一个过程,加载数据和创建表同时完成(CREATE EXTERNAL TABLE ……LOCATION),实际数据是存储在LOCATION后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个External Table时,仅删除该链接。
    外部表简单示例:
    创建数据文件:test_external_table.txt
    创建表:create external table test_external_table (key string)
    加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table
    查看数据:select * from test_external_table;  •select count(*) from test_external_table
    删除表:drop table test_external_table

(4)分区

    Partition对应于数据库中的Partition列的密集索引,但是Hive中Partition的组织方式和数据库中的很不相同。在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition的数据都存储在对应的目录中。例如pvs表中包含ds和city两个Partition,则对应于ds = 20090801, ctry = US 的HDFS子目录为/wh/pvs/ds=20090801/ctry=US;对应于 ds = 20090801, ctry = CA 的HDFS子目录为/wh/pvs/ds=20090801/ctry=CA。

    分区表简单示例:
    创建数据文件:test_partition_table.txt
    创建表:create table test_partition_table (key string) partitioned by (dt string)
    加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_table partition (dt=‘2006’)
    查看数据:select * from test_partition_table;  select count(*) from test_partition_table
    删除表:drop table test_partition_table

(5)桶

    Buckets是将表的列通过Hash算法进一步分解成不同的文件存储。它对指定列计算hash,根据hash值切分数据,目的是为了并行,每一个Bucket对应一个文件。例如将user列分散至32个bucket,首先对user列的值计算hash,对应hash值为0的HDFS目录为/wh/pvs/ds=20090801/ctry=US/part-00000;hash值为20的HDFS目录为/wh/pvs/ds=20090801/ctry=US/part-00020。如果想应用很多的Map任务这样是不错的选择。

    桶的简单示例:
    创建数据文件:test_bucket_table.txt
    创建表:create table test_bucket_table (key string) clustered by (key) into 20 buckets
    加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table
    查看数据:select * from test_bucket_table;  set hive.enforce.bucketing = true;

(6)Hive的视图

    视图与传统数据库的视图类似。视图是只读的,它基于的基本表,如果改变,数据增加不会影响视图的呈现;如果删除,会出现问题。•如果不指定视图的列,会根据select语句后的生成。
    示例:create view test_view as select * from test

Hive的执行原理


HIVE体系结构

 

图2.1 Hive的执行原理

    Hive构建在Hadoop之上, 
    (1)HQL中对查询语句的解释、优化、生成查询计划是由Hive完成的 
    (2)所有的数据都是存储在Hadoop中 
    (3)查询计划被转化为MapReduce任务,在Hadoop中执行(有些查询没有MR任务,如:select * from table)
    (4)Hadoop和Hive都是用UTF-8编码的

    Hive编译器将一个Hive QL转换操作符。操作符Operator是Hive的最小的处理单元,每个操作符代表HDFS的一个操作或者一道MapReduce作业。Operator都是hive定义的一个处理过程,其定义有:
protected List <Operator<? extends Serializable >> childOperators; 
protected List <Operator<? extends Serializable >> parentOperators; 
protected boolean done;   // 初始化值为false

    所有的操作构成了Operator图,hive正是基于这些图关系来处理诸如limit, group by, join等操作。

HIVE体系结构

图2.2 Hive QL的操作符

    操作符如下:
    TableScanOperator:扫描hive表数据
    ReduceSinkOperator:创建将发送到Reducer端的<Key,Value>对
    JoinOperator:Join两份数据
    SelectOperator:选择输出列
    FileSinkOperator:建立结果数据,输出至文件
    FilterOperator:过滤输入数据
    GroupByOperator:GroupBy语句
    MapJoinOperator:/*+mapjoin(t) */
    LimitOperator:Limit语句
    UnionOperator:Union语句
    Hive通过ExecMapper和ExecReducer执行MapReduce任务。在执行MapReduce时有两种模式,即本地模式和分布式模式 。

    Hive编译器的组成:

  HIVE体系结构

  HIVE体系结构

图2.3 Hive编译器的组成

    编译流程如下:

  HIVE体系结构
HIVE体系结构
图2.4 Hive QL编译流程

Hive和数据库的异同

    由于Hive采用了SQL的查询语言HQL,因此很容易将Hive理解为数据库。其实从结构上来看,Hive和数据库除了拥有类似的查询语言,再无类似之处。数据库可以用在Online的应用中,但是Hive是为数据仓库而设计的,清楚这一点,有助于从应用角度理解Hive的特性。

    Hive和数据库的比较如下表:

   

 

Hive 

RDBMS 

查询语言 

HQL

SQL

数据存储 

HDFS

Raw Device or Local FS 

数据格式

用户定义

系统决定

数据更新

不支持

支持

索引 

执行 

MapReduce 

Executor

执行延迟 

处理数据规模 

可扩展性


     (1)查询语言。由于 SQL 被广泛的应用在数据仓库中,因此专门针对Hive的特性设计了类SQL的查询语言HQL。熟悉SQL开发的开发者可以很方便的使用Hive进行开发。
     (2)数据存储位置。Hive是建立在Hadoop之上的,所有Hive的数据都是存储在HDFS中的。而数据库则可以将数据保存在块设备或者本地文件系统中。
     (3)数据格式。Hive中没有定义专门的数据格式,数据格式可以由用户指定,用户定义数据格式需要指定三个属性:列分隔符(通常为空格、”\t”、”\x001″)、行分隔符(”\n”)以及读取文件数据的方法(Hive中默认有三个文件格式TextFile,SequenceFile以及RCFile)。由于在加载数据的过程中,不需要从用户数据格式到Hive定义的数据格式的转换,因此,Hive在加载的过程中不会对数据本身进行任何修改,而只是将数据内容复制或者移动到相应的HDFS目录中。而在数据库中,不同的数据库有不同的存储引擎,定义了自己的数据格式。所有数据都会按照一定的组织存储,因此,数据库加载数据的过程会比较耗时。
     (4)数据更新。由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不支持对数据的改写和添加,所有的数据都是在加载的时候中确定好的。而数据库中的数据通常是需要经常进行修改的,因此可以使用INSERT INTO ... VALUES添加数据,使用UPDATE ... SET修改数据。
     (5)索引。之前已经说过,Hive在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中的某些Key建立索引。Hive要访问数据中满足条件的特定值时,需要暴力扫描整个数据,因此访问延迟较高。由于MapReduce的引入, Hive可以并行访问数据,因此即使没有索引,对于大数据量的访问,Hive仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了Hive不适合在线数据查询。
     (6)执行。Hive中大多数查询的执行是通过Hadoop提供的MapReduce来实现的(类似select * from tbl的查询不需要MapReduce)。而数据库通常有自己的执行引擎。
     (7)执行延迟。之前提到,Hive在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致Hive执行延迟高的因素是MapReduce框架。由于MapReduce本身具有较高的延迟,因此在利用MapReduce执行Hive查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive的并行计算显然能体现出优势。
     (8)可扩展性。由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是和Hadoop的可扩展性是一致的(世界上最大的Hadoop集群在Yahoo!,2009年的规模在4000台节点左右)。而数据库由于ACID语义的严格限制,扩展行非常有限。目前最先进的并行数据库Oracle在理论上的扩展能力也只有100台左右。
     (9)数据规模。由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。

Hive元数据库
 

    Hive将元数据存储在RDBMS 中,一般常用的有MYSQL和DERBY。

    启动HIVE的元数据库时,需要进入到hive的安装目录
    启动derby数据库:/home/admin/caona/hive/build/dist/,运行startNetworkServer -h 0.0.0.0。

    连接Derby数据库进行测试:查看/home/admin/caona/hive/build/dist/conf/hive-default.xml。找到

package org.apache.hadoop.hive.ql.udf;   
  
  public class UDFTestLength extends UDF {  
    public Integer evaluate(String s) {  
      if (s == null) {  
        return null;  
      }  
    return s.length();  
    }  
  }  

    UDF 具有以下特性:
    * 用java写UDF很容易。
    * Hadoop的Writables/Text 具有较高性能。
    * UDF可以被重载。
    * Hive支持隐式类型转换。
    * UDF支持变长的参数。
    * genericUDF 提供了较好的性能(避免了反射)。

(5)UDAF(User-Defined Aggregation Funcation)

    例子:

public class UDAFCount extends UDAF {  
    public static class Evaluator implements UDAFEvaluator {  
      private int mCount;   
  
      public void init() {  
        mcount = 0;  
      }   
  
      public boolean iterate(Object o) {  
        if (o!=null)  
          mCount++;   
  
        return true;  
      }   
  
      public Integer terminatePartial() {  
        return mCount;  
      }   
  
      public boolean merge(Integer o) {  
        mCount += o;  
        return true;  
      }   
  
      public Integer terminate() {  
        return mCount;  
      }  
  }  

    UDAF 总结:
    * 编写UDAF和UDF类似
    * UDAF可以重载
    * UDAF可以返回复杂类
    * 在使用UDAF的时候可以禁止部分聚合功能
    UDF,UDAF和MR脚本的对比:

HIVE体系结构
图7.2 UDF/UDAF/MR脚本比较

相关推荐