Hive原理

相对于hadoop复杂的job(MapReduce)编写过程,Hive提供了HQL(类似于SQL的)语言来高效的生成查询job,方便数据工程师在不会编程的情况下,进行并专注于数据分析。从本质上讲,Hive同Pig一样,都是一种简化批处理任务编程复杂度的工具,下面我们就来总体认识一下。

服务端组件

  • Driver组件:该组件包括:CompilerOptimizerExecutor,它可以将Hive的HQL进行编译、解析、优化后,最终转化为MapReduce任务提交给Hadoop 1中的JobTracker,或者Hadoop 2中的ResourceManager来执行实际的任务。

  • MetaStore组件:存储着Hive的元数据信息,Hive将自己的元数据存储到了关系型数据库当中,支持的数据库主要有:Mysql、Derby、支持把metastore独立出来放在远程的集群上面,使得hive更加健壮。元数据主要包括了表的名称、表的列、分区和属性、表的属性(是不是外部表等等)、表的数据所在的目录。

  • 用户接口:CLI(常用的接口:命令行模式)、Client:Hive的客户端用户连接至Hive Server, 在启动Client的时候,需要指定Hive Server所在的节点,并且在该节点上启动Hive Server、Web UI:通过浏览器的方式访问Hive。

任务执行流程

  1. 用户提交查询等任务给Driver
    1. Compiler获得该用户的任务Plan;
    2. Compiler根据用户任务去MetaStore中获取需要的Hive的元数据信息;
    3. Compiler得到元数据信息,对任务进行编译
      1. 先将HiveQL转换为抽象语法树
      2. 然后将抽象语法树转换成查询块
      3. 将查询块转化为逻辑的查询计划
      4. 重写逻辑查询计划,将逻辑计划转化为物理的计划
      5. 最后选择最佳的策略
    4. 将最终的计划提交给Driver
  2. Driver将计划Plan转交给ExecutionEngine去执行,获取元数据信息,提交给JobTracker或者ResourceManager执行该任务,任务会直接读取HDFS中文件进行相应的操作;
  3. 获取执行的结果;
  4. 取得并返回执行结果。

数据模型

  • Table
    类似于传统数据库中的Table,每一个Table在Hive中都有一个相应的目录来存储数据。例如:一个表t,它在HDFS中的路径为:/user/hive/warehouse/t内部表做删除表,就删除了目录及数据

  • External Table
    指向已存在HDFS中的数据,可创建Partition。数据是存储在Location后面指定的HDFS路径中的,并不会移动到数据仓库中。删除外部表,只是删除了元数据的信息,该外部表所指向的数据是不会被删除

  • Partition

    在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition数据都存储在对应的目录中。例如:t表中包含ds和city两个Partition,则对应于ds=2014,city=beijing的HDFS子目录为:/user/hive/warehouse/t/ds=2014/city=Beijing;需要注意的是,分区列是表的伪列,表数据文件中并不存在这个分区列的数据。一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。分区避免 Hive Select查询中扫描整个表内容,防止消耗很多时间做没必要的工作(相当于只查询了子表<子目录>)。

  • Buckets

    对指定列计算的hash,根据hash值切分数据,目的是为了便于并行,每一个Buckets对应一个文件。将user列分至32个Bucket上,首先对user列的值计算hash,比如,对应hash=0的HDFS目录为:/user/hive/warehouse/t/ds=2014/city=Beijing/part-00000;对应hash=20的目录为:/user/hive/warehouse/t/ds=2014/city=Beijing/part-00020

    buckets是对partition的一种补充,具体见以下例子:

    假设我们有一张日志表,我们需要按照日期和用户id来分区,目的是为了加快查询谁哪天干了什么。但是这里面用user_id去切分的话,就会产生很多很多的分区了,这些分区可大可小,这个数量是文件系统所不能承受的。
    在这种情况下,我们既想加快查询速度,又避免出现如此多的小分区,篮子(bucket)就出现了。

    1
    2
    3
    CREATE TABLE weblog (user_id INT, url STRING, source_ip STRING)
    > PARTITIONED BY (dt STRING)
    > CLUSTERED BY (user_id) INTO 96 BUCKETS;

    首先按照日期分区,分区结束之后再按照user_id把日志放在96个篮子,这样同一个用户的所有日志都会在同一个篮子里面,并且一个篮子里面有好多用户的日志。

操作实践

创建一个库表,表名为 cwqsolo, 含有2个字段 id, name,并且记录中各个字段的分割符为 ‘,’,在ascii中表示为 ‘\054’;

1
CREATE TABLE cwqsolo(id INT, name STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\054’;

修改字段名为ID的字段,修改后名称为 myid, string类型

1
ALTER TABLE cwqsolo CHANGE id myid String;

增加一个字段,字段名为 sex,性别

1
ALTER TABLE cwqsolo ADD COLUMNS (sex STRING COMMENT 'sex type');

加载文件

1
2
3
4
[root@archive studydata]# vi  test1.txt  
1001,cwq,male
1101,lxj,female
hive> LOAD DATA LOCAL INPATH '/home/hadoop/hive/studydata/test1.txt' INTO TABLE cwqsolo;

插入条目

1
2
insert into  table cwqsolo values ( '1005', 'ddd','male' );   # 追加
insert overwrite table test_insert select * from test_table; # 覆盖

执行SQL文本

1
hive -f /home/hadoop/hive/sql/creat_table_biss.sql

导出文本到本地

1
2
3
insert overwrite local directory '/home/data/cwq/' select * from  zc_bicc_isup_bdr  where  calling= '13003097698'; 

insert overwrite local directory '/home/data/cwq/output1’ row format delimited fields terminated by ',' select * from zc_bicc_isup_bdr where calling= '13003097698’; # 指定分隔符

0%