本节我们主要来学习一些hive的命令操作,同时探究一下Hive,HDFS,MySQL之间的联系,从而更好的理解其内部原理。
常用的基础命令
#此处的命令都是指在hive命令行下执行的命令,所有的命令别忘记以分号结尾。hive> show databases;#查看当前数据库列表hive> create databases dbname;#创建一个名称为dbname的数据库hive> use databasename;#将当前的数据库切换为databasenamehive> show tables;#查看当前数据库中有哪些表hive> desc tbname;#查看表结构,包括字段类型,注释等
Hive的数据类型
hive基本数据类型
hive集合数据类型
注:图片来自《hive编程指南》
这里先简单了解一下Hive的数据类型,本节我们暂时不会用到太多很复杂的类型。
建表
假设我们现在建立一张student
表,它有两个字段,id(int)
和name(string)
。
hive> create database learn;#创建数据库learnhive> use learn;#切换到learn数据库hive> create table student(id int, name string);#创建表studenthive> show create table student;#查看建表语句
创建表,查看建表语句
我们通过show create table student;
命令查看student
表建立时一些详细信息。关注一下LOCATION
的值为:hdfs://localhost:8020/user/hive/warehouse/learn.db/student
,猜测这是一个HDFS的文件路径,我们通过浏览器验证一下:
在浏览器中查看student表的location
可以看到,我们建立的student
表是HDFS上的一个目录(文件夹),目录的位置就是LOCATION
对的值。
将本地文件加载到Hive表
本地文件:当前目录下的student.txt
,字段之间用空格分割,
1 zhangsan2 lisi3 wangwu
hive> load data local inpath 'student.txt' into table student;
加载本地数据
加载成功之后,我们先来看一下HDFS中student目录,如下图所示,可以看到该目录下出现了一个student文件。
查看HDFS中student目录
然后用hive命令查询一下student表。
hive> select * from student;OKNULL NULLNULL NULLNULL NULLTime taken: 0.139 seconds, Fetched: 3 row(s)
可以看到结果虽然是有三行,但全部否是null。如果执行select count(*) from student;
也能输出结果为3。
查询student表的行数
出现这种情况是,我们建表时没有指定数据列之间的分隔符,hive默认的字段分隔符是\001,即ASCII码的第一个字符Control-A
,而我们的文件的分隔符是空格,二者不一致是导致数据不能正确加载的原因。
接下来我们创建一个新的表并指定分隔符为\t
,即tab符,然后重新加载以\t
分割的本地文件。
hive> create table teacher(id int, name string) row format delimited fields terminated by '\t';#创建teacher表并指定行分隔符为'\t'hive> load data local inpath 'teacher.txt' into table teacher;#实际运行加了overwrite,表示覆盖表中已有的数据,如果不加overwrite就会在已有的数据后直接添加。
加载tab符分割的数据
创建teacher表同样在HDFS中建立了相应的目录,load数据同样也将本地的数据加载到了相应的目录中。
HDFS中查看teacher目录
将HDFS文件加载到Hive表
我们按照以下的步骤进行操作:
①在本地建立course.txt
文件,写入三行内容,字段之间用空格分割。
1 语文2 数学3 体育
②将course.txt
上传到HDFS中并检查是否上传成功。
③在hive中建立course
表,指定分隔符为tab符
④执行load data inpath '/course.txt' into table course
命令,加载HDFS数据到course表中。
⑤查询course
表中的数据,验证是否成功加载
⑥查看HDFS中是否依然存在course.txt
文件。
从执行的结果我们可以看出,从HDFS中加载数据时,是将HDFS中的文件直接移动到了表对应的HDFS目录中(内部表)。
理解Hive的元数据
Hive环境搭建的时候我们使用MySQL存储了Hive元数据,并且在初始化时生成了很多mysql数据表。那么它们有什么作用呢?我们来看一下TBLS,COLUMNS_V2,SDS三个表的信息,很容易联系到我们前面创建的表。
mysql> use metastore;#切换到我们之前创建的元数据库。mysql> show tables;+---------------------------+| Tables_in_metastore |+---------------------------+| BUCKETING_COLS || CDS || COLUMNS_V2 || COMPACTION_QUEUE || COMPLETED_TXN_COMPONENTS || DATABASE_PARAMS || DBS || DB_PRIVS || DELEGATION_TOKENS || FUNCS || FUNC_RU || GLOBAL_PRIVS || HIVE_LOCKS || IDXS || INDEX_PARAMS || MASTER_KEYS || NEXT_COMPACTION_QUEUE_ID || NEXT_LOCK_ID || NEXT_TXN_ID || NOTIFICATION_LOG || NOTIFICATION_SEQUENCE || NUCLEUS_TABLES || PARTITIONS || PARTITION_EVENTS || PARTITION_KEYS || PARTITION_KEY_VALS || PARTITION_PARAMS || PART_COL_PRIVS || PART_COL_STATS || PART_PRIVS || ROLES || ROLE_MAP || SDS || SD_PARAMS || SEQUENCE_TABLE || SERDES || SERDE_PARAMS || SKEWED_COL_NAMES || SKEWED_COL_VALUE_LOC_MAP || SKEWED_STRING_LIST || SKEWED_STRING_LIST_VALUES || SKEWED_VALUES || SORT_COLS || TABLE_PARAMS || TAB_COL_STATS || TBLS || TBL_COL_PRIVS || TBL_PRIVS || TXNS || TXN_COMPONENTS || TYPES || TYPE_FIELDS || VERSION |+---------------------------+53 rows in set (0.00 sec)
mysql> select * from TBLS;#存放我们已经建立的表,具体字段如图所示mysql> select * from COLUMNS_V2;#存放表的字段,CD_ID是外键mysql> select * from SDS;#存放表的LOCATION和格式信息
注:这个表横向太长了。因此截成了两段,凑合看。感兴趣的可以自己动手试试。
TBS存放的是我们已经创建的表,COLUMNS_V2存放了标的字段信息,SDS存放了表的LOCATION和格式信息。其他表的信息我们也可以通过看里面的内容理解其作用请读者自行了解
其他命令
查看某个表的基本信息:
hive> desc student;#查看表的字段及其类型OKid intname stringTime taken: 0.069 seconds, Fetched: 2 row(s)hive> desc formatted student;#查看表的详细信息,包括字段,位置,类型,存储信息等OK# col_name data_type commentid intname string# Detailed Table InformationDatabase: learnOwner: chenghengchaoCreateTime: Sat Jun 08 00:31:45 CST 2019LastAccessTime: UNKNOWNProtect Mode: NoneRetention: 0Location: hdfs://localhost:8020/user/hive/warehouse/learn.db/studentTable Type: MANAGED_TABLETable Parameters: COLUMN_STATS_ACCURATE true numFiles 1 numRows 0 rawDataSize 0 totalSize 27 transient_lastDdlTime 1559973358# Storage InformationSerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeInputFormat: org.apache.hadoop.mapred.TextInputFormatOutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatCompressed: NoNum Buckets: -1Bucket Columns: []Sort Columns: []Storage Desc Params: serialization.format 1Time taken: 0.059 seconds, Fetched: 32 row(s)
在hive命令下直接操作HDFS:
# 在hive下直接操作HDFS,建立data文件夹并上传本地文件到HDFS,命名为a.txt 和b.txthive> dfs -mkdir /data;hive> dfs -put student.txt /data/a.txt;hive> dfs -put student.txt /data/b.txt;
表的类型有两种MANAGED_TABLE和EXTERNAL_TABLE。
hive内部表和外部表的区别
1)创建表时:创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径, 不对数据的位置做任何改变。
2)删除表时:在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据reference:https://blog.csdn.net/u010886217/article/details/83796151
reference:https://www.jianshu.com/p/ac2eca9181be
reference:https://blog.csdn.net/qq\_36743482/article/details/78393678
#创建外部表并指向已有的data目录,如果指定的location不存在则会创建。hive> create external table ext_student(id bigint,name string) row format delimited fields terminated by '\t' location '/data';OKTime taken: 0.064 secondshive> select * from ext_student;OK1 zhangsan2 lisi3 wangwu1 zhangsan2 lisi3 wangwuTime taken: 0.034 seconds, Fetched: 6 row(s)
查询结果显示了6条记录,前3条和后3条是一样的。这是因为/data 下面有两个文件a.txt 和b.txt,每个文件有3行有数据。如果再上传一次teacher文件到/data目录下。在看ext_student中的数据
hive> dfs -put teacher.txt /data/c.txt;hive> select * from ext_student;OK1 zhangsan2 lisi3 wangwu1 zhangsan2 lisi3 wangwu1 赵老师2 王老师3 刘老师4 邓老师Time taken: 0.032 seconds, Fetched: 10 row(s)
可见,指定的location,即/data目录下的三个文件的数据都被加载到了ext_student中。事实上,无论是外部表还是内部表,只要把某个文件放到表的目录下,就会被扫描并被查询出来。查询的执行过程是先通过TBLS表找到student表,然后根据表id到COLUMNS_V2表查找这张表都有哪些字段,然后再根据表id到SDS表中查找应该到HDFS的那个目录下去查找数据。
Hive分区表
hive> create external table players(id bigint,name string) partitioned by (nation string) row format delimited fields terminated by '\t' location '/players';#执行后会在HDFS上创建/players目录,这是一个以nation分区的表OKTime taken: 0.095 secondshive> dfs -put china.txt /players;#将本地的china.txt上传到HDFS的players目录下hive> select * from players;#查询players表,发现结果是空的,但如果从浏览器中查看players牡蛎,发现文件china.txt存在。OKTime taken: 0.041 seconds
查询没有数据的原因,是没有上传文件到指定分区。我们换一种方式。
hive> load data local inpath 'china.txt' into table players partition(nation='China');Loading data to table learn.players partition (nation=China)Partition learn.players{nation=China} stats: [numFiles=1, numRows=0, totalSize=38, rawDataSize=0]OKTime taken: 0.242 secondshive> select * from players;OK1 zhangjike China2 yijianlian China3 subingtian ChinaTime taken: 0.045 seconds, Fetched: 3 row(s)
我们上传文件时指定分区,就能查询出结果。此时在HDFS上出现了一个nation=China
的目录,china.txt
被上传到了改该目录下。
我们试一下手动创建nation=USA
目录,并将usa.txt上传到该目录。再查询players
表
hive> dfs -mkdir /players/nation=USA;hive> dfs -put usa.txt /players/nation=USA;hive> select * from players;OK1 zhangjike China2 yijianlian China3 subingtian ChinaTime taken: 0.042 seconds, Fetched: 3 row(s)
查询的结果没有USA分区的数据,但从浏览器中查看确实已经存在了/players/nation=USA/usa.txt,并且usa.txt是有数据的。这是因为元数据库中没有记录USA这个分区。(看SDS表的话,只有nation=China的记录)。但如果此时使用load命令加载数据,则可以创建nation=USA的分区。在SDS表中也会出现nation=USA。
hive> load data local inpath 'usa.txt' into table players partition(nation='USA');Loading data to table learn.players partition (nation=USA)Partition learn.players{nation=USA} stats: [numFiles=2, numRows=0, totalSize=50, rawDataSize=0]OKhive> select * from players;OK1 zhangjike China2 yijianlian China3 subingtian China1 Curry USA2 Phelps USA3 Woods USA1 Curry USA2 Phelps USA3 Woods USATime taken: 0.037 seconds, Fetched: 9 row(s)
查询的结果中出现了USA分区,但是有重复。这是因为nation=USA目录下有两个相同内容的文件。原因是通过load命令将目录“变”为分区的同时,也加载了相同的一份数据。我们也可以看出:分区一定是一个目录,但目录不一定是分区。而且如果删除了分区,文件夹可以继续存在,如果删除了文件夹,分区也继续存在。
我们也可以通过另一种方式修改(增加)分区,如下面命令所示。如果直接运行该命令,会在HDFS上创建目录nation=Other。如果我们先用mkdir创建nation=Other目录,再使用该命令,也可以将目录“变”为分区,此时目录下的文件就会被加载到表中,读者可以自行验证。
hive> alter table players add partition(nation='Other') location '/players/nation=Other';
再总结一下查看和删除分区的命令。
hive> show partitions players;#查看分区OKnation=Chinanation=Othernation=USATime taken: 0.047 seconds, Fetched: 3 row(s)hive> alter table players drop if exists partition (nation='Other');#删除某个分区Dropped the partition nation=OtherOKTime taken: 0.068 seconds
使用了分区之后,最大的好处是能提高查询的速度,同时也对数据进行了更细粒度的划分。可以使用where关键字限制分区。
hive> select * from players where nation = 'China';OK1 zhangjike China2 yijianlian China3 subingtian ChinaTime taken: 0.074 seconds, Fetched: 3 row(s)hive> select * from players where nation = 'USA';OK1 Curry USA2 Phelps USA3 Woods USA1 Curry USA2 Phelps USA3 Woods USATime taken: 0.047 seconds, Fetched: 6 row(s)
总结
本文我们对Hive的一些基础知识进行了学习,包括查看数据库,查看表的基本命令,如何建表并加载数据,hive元数据的存储位置,hive分区表与HDFS的关系等。通过学习我们对Hive底层原理有了更为深刻的认识。
以清净心看世界;
用欢喜心过生活。
超哥的杂货铺,你值得拥有~
长按二维码关注我们
推荐阅读:
本文分享自微信公众号 - 超哥的杂货铺(gh_a624b94bfdab)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。