Hive

概述

Hive是建立在Hadoop上的数据仓库基础架构。它提供了一系列的工具,用来进行数据提取、转换、加载,这是一种可以存储、查询和分析存储在Hadoop中的大规模数据机制。可以把Hadoop下结构化数据文件映射为一张成Hive中的表,并提供类sql查询功能,除了不支持更新、索引和事务,sql其它功能都支持。可以将sql语句转换为MapReduce任务进行运行,作为sql到MapReduce的映射器。提供shell、JDBC/ODBC、Thrift、Web等接口。

Hive 并不适合那些需要低延迟的应用,例如,联机事务处理(OLTP)。Hive 查询操作过程严格遵守Hadoop MapReduce 的作业执行模型,Hive 将用户的HiveQL 语句通过解释器转换为MapReduce 作业提交到Hadoop 集群上,Hadoop 监控作业执行过程,然后返回作业执行结果给用户。Hive 并非为联机事务处理而设计,Hive 并不提供实时的查询和基于行级的数据更新操作。Hive 的最佳使用场合是大数据集的批处理作业,例如,网络日志分析。

元数据存储

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

  • 内嵌模式:元数据保持在内嵌数据库的Derby,一般用于单元测试,只允许一个会话连接。
  • 多用户模式:在本地安装Mysql,把元数据放到Mysql内。
  • 远程模式:元数据放置在远程的Mysql数据库。

数据存储

Hive没有专门的数据存储格式,也没有为数据建立索引,用于可以非常自由的组织Hive中的表,只需要在创建表的时候告诉Hive数据中的列分隔符和行分隔符。
Hive中所有的数据都存储在HDFS中,Hive中包含4中数据模型:Tabel、ExternalTable、Partition、Bucket。

Table

类似与传统数据库中的Table,每一个Table在Hive中都有一个相应的目录来存储数据。例如:一个表zz,它在HDFS中的路径为:/wh/zz,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir}指定的数据仓库的目录,所有的Table数据(不含External Table)都保存在这个目录中。

Partition

类似于传统数据库中划分列的索引。在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition数据都存储在对应的目录中。例如:zz表中包含ds和city两个Partition,则对应于ds=20140214,city=beijing的HDFS子目录为:/wh/zz/ds=20140214/city=Beijing。

ExternalTable

指向已存在HDFS中的数据,可创建Partition。和Table在元数据组织结构相同,在实际存储上有较大差异。Table创建和数据加载过程,可以用统一语句实现,实际数据被转移到数据仓库目录中,之后对数据的访问将会直接在数据仓库的目录中完成。删除表时,表中的数据和元数据都会删除。ExternalTable只有一个过程,因为加载数据和创建表是同时完成。时间数据是存储在Location后面指定的HDFS路径中的,并不会移动到数据仓库中。

Bcuket

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

Hive QL

  • create table

    create table test_user(id int,name string) 
    // 注释
    comment 'This is the test table'
    row format delimited
    // 指定切分格式规则
    fields terminated by ','
    // 指定文件格式
    stored as textfile;
  • insert select

    //使用select语句来批量插入数据
    insert overwrite table test_user select * from tab_user;
  • load data

    //从本地导入数据到hive的表中(实质就是将文件上传到hdfs中hive管理目录下)
    load data local inpath '/home/hadoop/test.txt' into table test_user;
    //从hdfs上导入数据到hive表中(实质就是将文件从原始目录移动到hive管理的目录下)
    load data inpath 'hdfs://ns1/data.log' into table test_user;
  • external table

    //LOCATION指定的是hdfs路径
    //如果LOCATION路径有数据,则可以直接映射数据建表
    CREATE EXTERNAL TABLE test_user_external(id int, name string)
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY ','
    STORED AS TEXTFILE
    LOCATION '/external/user';
  • CTAS

    //CTAS是通过查询,然后根据查询的结果来建立表格的一种方式。
    //CTAS会根据SELECT语句创建表结构,并把数据一并复制过来。
    CREATE TABLE test_user_ctas
    AS
    SELECT id new_id, name new_name
    FROM test_user
    SORT BY new_id;
  • Partition

    //创建一个分区表,以year年份作为分区字段
    create table test_user_part(id int,name string)
    partitioned by (year string)
    row format delimited fields terminated by ',';
    //将data.log导入到test_user_part表中,并设置分区为1990
    load data local inpath '/home/hadoop/data.log' overwrite into table test_user_part
    partition(year='1990');

    load data local inpath '/home/hadoop/data2.log' overwrite into table test_user_part
    partition(year='2000');
  • Array&&Map:
    hive中的列支持使用struct、map和array集合数据类型。大多数关系型数据库中不支持这些集合数据类型,因为它们会破坏标准格式。关系型数据库中为实现集合数据类型是由多个表之间建立合适的外键关联来实现。在大数据系统中,使用集合类型的数据的好处在于提高数据的吞吐量,减少寻址次数来提高查询速度。

    //array 
    create table tab_array(a array<int>,b array<string>)
    row format delimited
    fields terminated by '\t'
    collection items terminated by ',';
    select a[0] from tab_array;
    select * from tab_array where array_contains(b,'word');
    insert into table tab_array select array(0),array(name,ip) from tab_ext t;

    //map
    create table tab_map(name string,info map<string,string>)
    row format delimited
    fields terminated by '\t'
    collection items terminated by ','
    map keys terminated by ':';
    load data local inpath '/home/hadoop/hivetemp/tab_map.txt' overwrite into table tab_map;
    insert into table tab_map select name,map('name',name,'ip',ip) from tab_ext;

Hive常用优化方法

  • join连接时的优化:当三个或多个以上的表进行join操作时,如果每个on使用相同的字段连接时只会产生一个mapreduce。
  • join连接时的优化:当多个表进行查询时,从左到右表的大小顺序应该是从小到大。原因:hive在对每行记录操作时会把其他表先缓存起来,直到扫描最后的表进行计算。
  • 在where字句中增加分区过滤器。
  • 当可以使用left semi join 语法时不要使用inner join,前者效率更高。原因:对于左表中指定的一条记录,一旦在右表中找到立即停止扫描。
  • 如果所有表中有一张表足够小,则可置于内存中,这样在和其他表进行连接的时候就能完成匹配,省略掉reduce过程。设置属性即可实现,set hive.auto.covert.join=true; * 用户可以配置希望被优化的小表的大小 set hive.mapjoin.smalltable.size=2500000; 如果需要使用这两个配置可置入$HOME/.hiverc文件中。
  • 同一种数据的多种处理:从一个数据源产生的多个数据聚合,无需每次聚合都需要重新扫描一次。
  • 例如:insert overwrite table student select  from employee; insert overwrite table person select from employee;
  • 可以优化成 from employee insert overwrite table student select insert overwrite table person select
  • limit调优:limit语句通常是执行整个语句后返回部分结果。set hive.limit.optimize.enable=true;
  • 开启并发执行。某个job任务中可能包含众多的阶段,其中某些阶段没有依赖关系可以并发执行,开启并发执行后job任务可以更快的完成。设置属性:set * hive.exec.parallel=true;
  • hive提供的严格模式,禁止3种情况下的查询模式。
    • 当表为分区表时,where字句后没有分区字段和限制时,不允许执行。
    • 当使用order by语句时,必须使用limit字段,因为order by 只会产生一个reduce任务。
    • 限制笛卡尔积的查询。
  • 合理的设置map和reduce数量。
  • jvm重用。可在hadoop的mapred-site.xml中设置jvm被重用的次数。