Hive简介

hive入門 hive详解_hive入門


hive详解 hive入门必看

hive入門 hive详解_分区分桶_02


上图是OLAP引擎整体架构图,分为三个层面:数据存储层,计算资源层以及OLAP服务层。(我们从olap引入hive,如果重点关注hive,这部分作为扩展即可。)

• OLAP引擎是基于Spark和Hadoop的SQL引擎,内部依赖Druid,HDFS,HIVE存储来存储相关数据。为了与离线计算集群解耦,OLAP自身内部有一套完整的HDFS存储,HIVE存储以及Yarn资源池。

• OLAP引擎外部对底层HIVE访问需要通过API层进行转发,比如新增分区,修改表结构等,运行在离线计算集群上的加速等任务无法操作OLAP引擎底层Hive数据仓库。

-----数据仓库-----

Hive是数据仓库,与传统的数据库(mysql、oracle等)不同,但是hive也并不是Nosql。数据库主要处理用于事务处理,也就是对操作性数据进行增删改查;而数据仓库主要作用于分析处理、挖掘信息,可以说hive只适合于批量数据的统计分析。数据仓库就等同于一种分析型数据库。

Hive与传统数据库的比较:

HIVE

RDBMS

存储位置

Hdfs

LocalFS

查询语言

Hql

Sql

执行

MR

Executor

执行延迟



处理规模



可扩展性



加载模式

读时模式

写时模式

对关系型数据库而言,加载数据时就会检查数据是否符合表模式,不符合就会拒绝加载,叫做“写时模式”,写时模式在加载数据时会校验数据,并且会对数据建索引,压缩数据,所以加载数据会很慢,但是加载完成后查询时,速度会很快;而hive在加载数据时不会去检查数据,你可以load任何格式的数据,包括图片等都可以load进去,但是在select的时候会检查表内数据格式,叫做“读时模式”。

-----存储-----

Hive的元数据存储在关系型数据库中;表数据存储依赖于hdfs,是存储在hdfs上的,具体又分为内部表和外部表:

① 内部表数据由Hive自身管理,外部表数据由HDFS管理;

② 删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;

③ 无论内部表还是外部表,导入hdfs数据是mv,导入本地数据是copy

1) 元数据(metadata)

元数据是用来存储表数据信息的,比如表名,字段名,字段类型,存储位置等等,通常存储在mysql中,mysql地址可从hive-site.xml查找。

SELECT count(*) TABLES, table_schema FROM information_schema.TABLES where table_schema = ‘hive_bigquery_metastore’ GROUP BY table_schema;

hive入門 hive详解_列存与行存_03


2)内部表(managed table):

内部表数据由Hive自身管理,因为底层是hdfs,所以,所谓的hive内部是相对于外部表来说的,数据还是存储在hdfs上。

Hive默认建的是内部表:

create table test_inout(A int,name string); //建表语句,建表成功后,会在hdfs上新建存储该表数据的目录;

load data inpath ‘/user/olap/hive/4.txt’ into table test_inout; //导入hdfs上的数据,导入之后可以在50070页面查看变化,一个是看’/user/olAp/hive/4.txt’已经被删除,转移到test_inout目录下了。

hive入門 hive详解_hql转mapreduce_04


默认分隔符是^A,ASCII的码控制符\001,用ctrl+v然后再ctrl+a可以敲出来,所以一般建表时会指定分隔符

create table test_inn(id int,name string) fields terminated by ‘,’;

假如load的数据文件分隔符与表约定的分隔符不一致,仍可load成功,但是查询时会是null数据。这是hive的一个特性:load数据时不会做格式检查,只是将文件拷贝到对应的目录下,在查询时才会将文件数据与表定义的格式做比较。

当删除内部表时,底层hdfs的数据同步被删除,这是内部表与外部表的区别之一。

3)外部表(external table)

外部表建表 与内部表建表语句类似,只是多了一个external。适用场景:同样的数据需要被多人分享时。比如对于一些原始日志文件,同时被多个部门同时操作的时候就需要使用外部表,如果不小心将meta data删除了,HDFS上 的data还在可以恢复,增加了数据的安全性。

create external table test_out (id int,name string) row format delimited fields terminated by ‘,’;

load data local inpath “/home/bigdata/shenyuqiang/out.txt” into table test_out;

hive入門 hive详解_hive_05


但是外部表不能使用truncate来清数据;而使用drop时,外部表只是删除meta信息,data数据还是存储在hdfs上不会被删掉,meta信息是否被删除可以去元数据库里tbls表里验证对于hdfs上数据是否删除,最直观的是检查50070页面,也可使用hdoop命令查看;不指定location建表,hive会在默认位置存放表数据

hive入門 hive详解_hive_06


总的来说,导入数据时,导入到内部表,是导入到自己的内部目录下,由hive管理;而导入到外部表则不由hive管理。

删除数据时,删除内部表,是同时删除了的元数据和表数据;而删除外部表数据只是删除了 元数据。

-----存储格式 parquet-----

官方:”为Hadoop生态系统中的任何项目提供压缩,高效的列式数据”

所以要了解parquet,先了解列存。列式存储(ColumnAr or column-bAsed)是相对于传统关系型数据库的行式存储(Row-bAsedstorAge)来说的。简单来说两者的区别就是如何组织表。

示例表,有3个字段

A(int)

B(string)

C(string)

1

B1

C1

2

B2

C2

3

B3

C3

行存储逻辑图

1

B1

C1

2

B2

C2

3

B3

C3

列存逻辑图

1

2

3

B1

B2

B3

C1

C2

C3

• 列存查询的时候不需要扫描全部的数据,而只需要读取每次查询涉及的列,这样可以将I/O消耗降低N倍
• 由于每一列的成员都是同质的,可以针对不同的数据类型使用更高效的数据压缩算法,进一步减小I/O。
• 由于每一列的成员的同构性,可以使用更加适合的编码方式。
存储方式主要分为行存与列存,二者互有优缺点:

行存

列存

数据写入

一次写入,数据完整性得到保证

拆分成多列写入,IO高

行存占优

数据修改

指定位置修改一次

需定位到多个列的位置写入,磁头移动高

行存占优

数据读取

整存整取,一次取出一行数据;行数据有多种类型字段,解析会消耗大量cpu

只取需要用到的列;数据同质,利于解析

列存更适于大数据分析

针对以上的优缺点,可以设想下如何优化: 行存缺点就是会产生冗余数据,第一,在设计表的时候就注意避免冗余列的产生; 第二是优化数据存储记录结构,保证从磁盘读取的数据进入内存后,能快速分解消除冗余列。 列存缺点是数据写入完整性不缺定、写入效率低,可以考虑在写入过程中加入类似关系型数据库中的“回滚”机制,一旦某列写失败,此前写入的数据全部失效;写入效率低的应对方案,可以增加硬盘的方式多线程并行写入,但是要考虑成本。 大多数公司的列存采用的是parquet存储格式,比如新建数据集等,面向分析的列存储文件格式;

hive入門 hive详解_hive入門_07

-----分区分桶-----

在hive select查询时,会扫描全表,对大数据来说,全表扫描消耗的时间是巨大的,甚至会卡死。所以引入分区的概念,只查询我们所关心的部分数据,简单来说分区就是集合,就是把一个或几个字段作为分区字段,符合分区条件的数据就会落到对应的分区集合中。企业中最常见的就是以时间作为分区,每天的数据入到当天的分区里,表下存在对应的分区目录, hdfs上可以明显的看到表与分区的层级关系。这样就大大提高了查询效率。但是在实际生产中,分桶策略使用频率较低,更常见的还是使用分区。

Create table test_partition (A int,name string) partitioned by (dates string);

hive入門 hive详解_hql转mapreduce_08


在表或分区之上,hive可以继续对数据进行更细粒度的划分,也就是分桶。

  1. 为什么分桶
    主要是为了获取更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大减少JOIN的数据量。
    以下面为例:select A.a,A.name,b.addr from A join b on A.a = b.a; 如果A表和b表已经是分桶表,而且分桶的字段是a字段,那么做这个操作的时候就不需要再进行全表笛卡尔积了,用8条数据测试二者相差2秒。
    create table t_buck(A int,name string) clustered by (A) into 4 buckets;
    【create table t_buck_copy(A int,name string);
    load data local inpath ‘/home/bigdata/shenyuqiang/hash.txt’ into table t_buck_copy;】
    set hive.enforce.bucketing= true; //强制分桶
    set mapreduce.job.reduces=4;
    insert into t_buck select * from t_buck_copy cluster by (A); //桶表不能通过load的方式直接加载数据,只能从另一张表中插入数据,且执行时,reduce个数与桶个数相同

    select * from t_buck tablesample(bucket 1 out of 4 on A);
    select test_inout.name,test_inn.name from test_inout,test_inn where test_inout.A = test_inn.A; 普通表
    select test_buck1.name,test_buck2.name from test_buck1,test_buck2 where test_buck1.A=test_buck2.A; 桶表


    2.怎么分桶–数据分桶的原理:
    跟MR中的HashPartitioner的原理一模一样
    MR中:按照key的hash值对reduceTask的个数取模。
    Hive中:按照分桶字段的hash值对分桶的个数做取模运算,以此决定该条记录存放在哪个桶当中,最大化程度上保证数据的平均分配。
    做hash运算时,hash函数的选择取决于分桶字段的数据类型
    抽样语句:select * from test_buck tablesample(bucket x out of y on A);
    x表示从哪个bucket开始抽取,y表示相隔多少个桶再抽取。y必须是table总bucket数的倍数或者因子
    例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,y=4时,抽取(4/4=)1个bucket; select * from test_buck tAblesAmple(bucket 1 out of 2 on A);

例如,table总bucket数为4,tablesample(bucket 1 out of 2),表示总共抽取(4/2=)2个bucket的数据,分别为第1个bucket和第(1+2=3)个bucket的数据。select * from test_buck tAblesAmple(bucket 1 out of 2 on A);
所以如果想看每个bucket里存储的数据,y取bucket个数的数值,x从1取到y
3.基于分区的基础上分桶

create table test_buck4(A int,name string) partitioned by (dates string) clustered by(A) sorted by (A asc) into 4 buckets row format delimited fields terminated by ‘,’;
insert into table test_buck4 partition(dates=‘20180909000000’) select A,name from test_buck4_copy where dates=’ 20180909000000’ cluster by (A);

hive入門 hive详解_分区分桶_09

-----Hql-----
Hive的出现目的是为了简化MapReduce编程,本着会sql的总比会Java的多的现象特点,但是hive分析数据底层的实现是转换成MR。成本低

CREATE TABLE test_0807_01(
 A int,
 name string)
 PARTITIONED BY (
 dates string)
 ROW FORMAT DELIMITED
 FIELDS TERMINATED BY ‘|’
 COLLECTION ITEMS TERMINATED BY ‘_’;


1)UDF用户自定义函数
编程步骤:

  1. 继承org.apache.hadoop.hive.ql.UDF
  2. 实现evaluate函数,该函数支持重载
    First, you need to create A new class that extends UDF, with one or more methods named evaluate.
    第二步,向hive环境中添加jar:add jar /home/bigdata/shenyuqiang/HiveUDF.jar;
    注册临时函数,create temporary function myudf as “hiveCon.MyUdf”;
    之后就可以使用了
    销毁临时函数的命令:drop temporary function xx
    2)核心:hql怎么转换成mapreduce

hive入門 hive详解_hive入門_10


驱动器:driver

包含:解析器、编译器、优化器、执行器

解析器:将sql字符串转换成抽象语法树AST,这一步一般都通过第三方工具库完成,比如Antlr;将AST进行语法分析,比如表是否存在、字段是否存在、sql语义是否有误.

编译器:将AST编译生成逻辑执行计划

优化器:对逻辑执行计划进行优化

执行器:把逻辑执行计划转换成可以运行的物理计划。对hive来说,就是翻译成mapreduce.

-----运维-----

日志定位

在启动hive的时候,可以看到日志初始化的信息,日志相关信息就配置在hive-log4j.properties文件中的hive.log.dir

hive入門 hive详解_列存与行存_11


通过修改以下配置,使打印出来的信息带db.tableName

hive入門 hive详解_分区分桶_12

几种临时参数的设置,只在当前有效,退出后失效。
hive> set mapred.reduce.tasks = 6; //hiveShell设置启动6个任务
hive --hiveconf hive.root.logger=INFO,console; //启动hive时设置将日志打印在控制台

在hive中也可操作dfs命令,查看hdfs文件系统

dfs -lsr /user/olap/hive/warehouse/olap.db;

hive入門 hive详解_分区分桶_13


同样,也支持部分操作本地文件系统的命令,需要在命令前加!

hive入門 hive详解_hive入門_14


Hive的几种交互方式

hive –help
 -d,–define <key=value> VAriAble subsitution to Apply to hive
 commAnds. e.g. -d A=B or --define A=B
 –database Specify the database to use
 -e SQL from command line
 -f SQL from files
 -H,–help Print help informAtion
 –hiveconf <property=value> Use value for given property
 –hivevar <key=value> VariAble subsitution to Apply to hive commands. e.g. --hivevar A=B
===============================
 -i InitiAlizAtion SQL file
 -S,–silent Silent mode in interActive shell
 -v,–verbose Verbose mode (echo executed SQL to the
 console)


修复分区的两种方式
msck repair table tablename;
alter table teblename add partition();
-----总结-----
HIVE:
*处理的数据存储在hdfs
*分析数据底层实现是mapreduce
*程序运行在yarn
Sql on hadoop
Hive的强大之处在于对数据的ETL处理
抽取(extract)、交互转换(transform)、加载(load)