Hive0.13.0简介

版权声明:本文为博主原创文章,欢迎转载,转载请注明出处。 https://blog.csdn.net/u012802702/article/details/51707230

好久不更新博客了,近几个月经过反复修改整理已经积攒了一堆笔记,恰好趁此更新博客的机会再将所学知识进行一个系统的回顾和梳理奋斗

一、Hive简介

1.1、Hive是建立在Hadoop上的数据仓库基础构架。

他提供了一系列的工具,可以用来进行数据提取和转化加载(ETL),是部署在hadoop集群上的,是hadoop集群上的一个框架,这是一种大规模的数据机制,Hive定义了简单的类SQL查询语句,称为HQL,他允许熟悉Sql的用户查询数据,同时,这个语言也允许熟悉MapperReducer开发者开发自定义的Mapper和Reduce来处理内置的Mapper和Reducer无法完成的复杂的分析工作。支持SwiftS

1.2、数据仓库与数据库的区别:

1、数据库可以实时的进行增删该查,
2、数据仓库不仅仅用于存放大量数据,同时支持对数据进行分析计算,但是不支持实时的更新删除,如发现有一条数据错误,不能直接修改,只能先将数据下载下来,在本地进行修改,之后再上传上去。同时不能删除某条数据,除非整个文件中只有一条数据,将整个文件删除。即数据仓库用于保存和分析数据,其中的数据是一次写入多次读取。

Hive是一个Sql解析引擎,可以解析SQL,将SQl解析成MapperReduce任务在Hadoop上执行,
Hive的表其实就是HDFS的文件夹,表里的数据对应于文件夹中的文件,按照表名把文件夹分开,如果是分区表,则分区值是子文件夹,可以直接在MapperReducer任务中使用这些数据。

1.3、用户接口:

CLI;命令行接口,即shell, 用的最多是使用脚本。因为JDBC存在问题,对并发和连接池支持不好。
JDBC/ODBC:是Hive的Java,与使用传统数据库JDBC的方式类似,支持多语言,其中有一个Thrift Server支持多语言,如使用c++写的会通过Thrift Server将其转换为SQL去操作Hive。
WebUI:浏览器,只能查看。

1.4、元数据库 (metaStore) :

Hive将原数据存储在元 数据库中(metaStore),元数据库保存数据的一些表、数据分区的一些简单的描述信息(如有哪些表,表中有哪些字段,有哪些分区等等),而海量的计算数据保存在HDFS中。

Hive的Driver包含解释器、编译器、优化器完成HQL查询语句从词法分析,语法分析,编译,优化以及查询计划(plan)的生成,生成的查询计划存储在Hdfs中,并在随后由MapperReducer进行调用。

Hive的数据存储在HDFS中默认将表存放到HDFS的:hdfs://ns1/user/hive/warehouse/目录下(ns1指的是NameService),大部分的查询会产生对应的MapperReducer,使用MapperReducer完成,但是包含* 的查询,例如SELECT * FROME table(即进行全表扫描) 不会生成MapperReducer,直接将HDFS中的数据读取出来即可。

1.5、元数据库问题:

当我创建表时,会在MateStore中保存表的元数据信息,同时在HDFS中创建表的对应目录用来保存表的数据。
详细信息:首先将表名,表中有几个字段,每个字段的类型,表中数据在HDFS的存放位置等元数据信息保存在元数据库(metaStore)中,而我们要计算的数据(即表中的数据)保存在HDFS中,默认将表保存在HDFS的文件夹为:/user/hive/ warehouse /表名

Hive中有默认的metaStore,且当Hive运行时即执行$HIVE_HOME /bin/hive命令时,会在 当前目录下会生成一个 metastore_db目录,用于保存元数据。且若连续两次在不同目录下执行$HIVE_HOME /bin/hive 命令,此时在哪个目录下执行 /bin/hive 命令 就去读哪个目录下的元数据库,若当前目录下没有则创建一个新的 metastore_db目录 。

默认的MateStore是一个 derby数据库但是他只支持一个连接,即对于一个MateStore(元数据库)同时只能有一个客户端进入Hive , 即在同一目录下多次运行$HIVE_HOME/bin/hive命令时会报错。此外derby数据库想要支持多连接,需要切换不同的目录执行$ HIVE_HOME/bin/hive 命令,这时会使用不同的 metastore_db目录,但二者不能共用表。

基于derby数据库的问题,实际开发中使用MySQL数据库。Mysql数据库的安装和配置,可查阅资料。

 安装数据库时,曾指定数据库安装在那个节点上,且MySQL数据库中是否已经有hive库,如果没有则在MySQL中创建名为hive的库,默认hive库中会有20几张表用来保存hive的元数据信息,其中 在TBLS表中保存有创建表的描述信息:表的ID,表名,表的字段,以及字段类型。在SDS表中存放有表对应存放在HDFS的目录位置,
     每张表在HDFS中以目录的形式存放,一个表对应一个目录(默认存放在 hdfs://ns1/user/hive/warehouse /目录下 ),且无论是内部表还是外部表,只要将数据文件存放到该表对应得HDFS目录中,数据文件就会被做为表的内容。也就是说使用SELECT * FROM 表明,语句查询表中所有内容时,会依次显示出该表对应的HDFS目录下的所有文件中的内容。


简述mateStore中表是怎样确定与HDFS目录关系的
     0】、当再Hive中创建一张表后,在 TBLS表,中会记录表的ID,表的名称,表所属用户,表的类型等等.... SD_ID是用于关联 SDS表 的。
    1】、 当查询某一张表时如student表,此时会在 TBLS表 中找到student表并确定student表对应的ID为2,
    2】、根据student表的ID去中 COLUMNS_V2表中找对应得关联字段CD_ID为2的记录,
如图中显示CD_ID为2,的记录就是对student表列字段信息的描述。从表中可以知道student表有两个字段:id 类型为 bigint,name类型为string
     3】、之后查 SDS表查找到student对应得信息,根据该条信息中LOCATION字段即可确定student表在HDFS文件系统中的存储位置。
1.6、在Hive中支持使用HDFS的命令,但需将命令开头的hadoop改为dfs
     查看HDFS的根目录:
hadoop默认命令: hadoop fs -ls /
在Hive中: dfs -ls /;
     在HDFS中创建名为data的目录
          hadoop默认命令: hadoop fs -mkdir /data
          Hive中的命令: dfs -mkdir /data;
     上传文件:
          Hive中: dfs -put /root/student.txt /data/a.txt;

二、使用Hive

2.1、建表(默认是内部表) ,

即先建一张表,将linux中的数据load到HDFS上,且有表相关联,此时在TBLS表中该表对应得那条数据(每条数据对应一张hive表的描述信息)中TBL_TYPE字段的值均为:MANAGED_TABLE
    
     在Hive安装的节点上,进入Hive模式,执行     
     create table student (id bigint, name string) row format delimited fields terminated by '\t';
     此时在HDFS的 hdfs://ns1 /user/hive/ warehouse /目录下会生成一个名为student的目录(文件夹),该目录对应的就 生成的表。
   
      将linux本地/root/student.txt文件数据导入到student表中:
      load data local inpath '/root/student.txt' into table student;
     此时在在DHFS的 /user/hive/ warehouse / 下 会多出一个文件:hdfs://ns1/user/hive/warehouse/student/student.txt
     
      查询student中所有数据: 
      select * from student;
      此时并不会执行MapperReduce,而直接显示student.txt中的数据
     
     查询前两条:
      select * from student limit 2;
      此时也不会执行MapperReducer,只需将所有数据全部读出来,显示前两条
   
     求和
     select sum(id) from student;
      此时转换成MapperReducer,且结果中没有加Null,因为id有类型的

值得注意的是: 此时如果再将一个文件(文件中数据格式满足表 student  定义格式)放/user/hive/warehouse/student/ 目录下那么该文件就会被做为 student 表的内容,且使用 select * from student; 语句查询 student表 中数据时会将 /user/hive/warehouse/student/ 目录下的 所有文件中的内容 依次显示出来


2.2、外部表:

先有数据后有表,例如:公司有一些历史数据,且已经上传到HDFS上了,此时创建一张表,将表指向该数据。注意上面是,数据(student.txt )存放在linux系统中,先创建表,然后将linux中的数据(student.txt )load 到HDFS系统中的。而若HDFS中已经存在数据了,可以直接创建外部表。此时是不允许使用load将数据加入外部表中的。

准备工作:
     在Hive中使用HDFS命令创建目录: /data
      dfs -mkdir /data;     
    将linux中的文件存入到/data中
      dfs -put /root/student.txt /data/a.txt;
外部表创建:
     创建一张表 ext_student指向HDFS中的 /data/目录即把他认为是一个表。
     create external table ext_student (id int,name string) row format delimited fields terminated by '\t' location '/data';
                查询数据:
                 select * from ext_student;

值得注意的是 此时如果再将一个文件(文件中数据格式满足表的定义id int,name string 且分割符为‘\t’)放到/data/目录下那么该文件就会被当做表的内容,使用 select * from ext_student; 语句查询 ext_student表中数据时会将 /data/目录下的 所有文件中的内容依次显示出来
但是有种特殊情况除外:



2.3、建分区表:

如将数据按照年份进行分区,之后再查询数据时,直接查找对应年份的分区数据即可,而不用按照年份字段进行全表扫描,减少查询时间。 而分区其实就是表对应目录下的子文件夹,

0】、创建表:
    create table td_part(id bigint, account string, income double) partitioned by (logdate string) row format delimited fields terminated by '\t' location '/part';
创建一个分区表,且为外部表,此时按照logdate string字段分区(在向表中加载HDFS中的文件数据时指定该文件属于哪个分区),并指向HDFS的/part目录(如果没有则会自动创建),
 
1】、在linux的/root目录下编写2个文件a.txt、b.txt数据格式按td_part定义的格式。数据如下:
      a.txt:
1     blw     1200
2     ssh     1300
     b.txt:
3     bxc     3000
4     ml     4000

2】、将a.txt于b.txt两个文件put上传到td_part表对应得HDFS目录中:/part. 但此时查询td_part表中数据(select * from td_part;)时并不会查出任何数据,因为没有定义分区。

      hadoop fs -put b.txt /part
     hadoop fs -put a.txt /part
而分区其实就是表对应目录下的子文件夹,因此直接放在/part目录下的文件是不会被td_part 查出来的,这就是上面所指的特殊情况。要想被查出来,就必须将数据文件放到对应得分区子文件夹中

3】、定义分区:将b.txt加载到td_part表中,并制定分区为today
      load data local inpath '/root/b.txt' into table td_part partition ( logdate ='today');
      此时在HDFS 的/part目录下会生成一个子目录/part/logdate=today/ 而数据文件b.txt只有存放到该子目录下才能被td_part查出来,查询td_part表中数据(select * from td_part;)会显示数据。

4】、另外。如果手动在HDFS中的/part中创建一个子目录:/part/logdate=tomorrow/之后将数据文件a.txt上传到该目录下,是否可以查出a.txt的数据?
     答案是 不可以,因为手动方式添加子目录时,元数据库MateStore中没有添加相关记录,因此当查询 td_part表时并不会去 /part/logdate=tomorrow/目录下扫描数据。需要使用Hive语句通知Hive:
      alert table td_part add partition (logdate='tomorrow') location "/part/logdate=tomorrow";
     此时就可以查询出 /part/logdate=tomorrow/ 目录下的数据了。
5】、按分区查询数据:
     select * from td_part where logdate='today';
      此时会直接显示对应分区目录中的数据。而不需要进行全表扫描。

附:一般实际应用中都是查询日志,所以可以按时间建立分区,且可以建多层分区,首先按月建分区,月下面还有日分区,

注意分区字段不能是表里的某个字段:
create table sms (id bigint,content string,area string) partitioned by (area string) row format delimited fields terminated by '\t';
会报错,说字段冗余,解决方法,可以建两个字段将数据保持一致

分区是以字段的形式在表结构中存在,通过describe table命令可以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。

猜你喜欢

转载自blog.csdn.net/u012802702/article/details/51707230