hive原理与实操(二):hive中数据定义(DDL)与数据管理(DML),初学者视角学hive。

文章目录

  • 前言
  • 1、hive数据类型
    • 1.1基本数据类型
    • 1.2 集合数据类型
    • 1.3 类型转化
  • 2、DDL数据定义
    • 2.1 数据库
      • 2.1.1 创建数据库
      • 2.1.2 查询数据库
      • 2.1.3 修改数据库
      • 2.1.4 删除数据库
    • 2.2 表
      • 2.2.1 内部表、外部表、分区表和分桶表简介
      • 2.2.1 创建表
      • 2.2.2 修改表
      • 2.2.3 删除表
  • 3、DML数据操作
    • 3.1 数据导入
      • 3.1.1 加载数据
      • 3.1.2 插入数据
    • 3.2 数据导出

前言

本文主要总结的是DDL和DML的相关语法,简单介绍了内部表、外部表、分区表、分桶表、序列化与反序列化的内容。希望能帮助到大家语法查询,也方便自己复习。任重道远,缓缓前行。

1、hive数据类型

1.1基本数据类型

Hive 数据类型 Java 数据类型 长度 例子
TINYINT byte 1byte 有符号整数 20
SMALINT short 2byte 有符号整数 20
INT int 4byte 有符号整数 20
BIGINT long 8byte 有符号整数 20
BOOLEAN boolean 布尔类型,true 或者false TRUE FALSE
FLOAT float 单精度浮点数 3.14159
DOUBLE double 双精度浮点数 3.14159
STRING string 字符系列。可以指定字 符集。可以使用单引号或者双 引号。 ‘ now is the time ’ “for all good men”
TIMESTAMP 时间类型
BINARY 字节数组

因为字符串有日期格式的字符串可以自动转换为日期类型,所以时间类型的数据基本不会用。用的较多的是INT、BIGINT、DOUBLE和STRING。

1.2 集合数据类型

数据类型 描述 语法示例
STRUCT 和 c 语言中的 struct 类似,都可以通过“点”符号访 问元素内容。例如,如果某个列的数据类型是 STRUCT{first STRING, last STRING},那么第 1 个元素可以通过字段.first 来 引用。 struct()例如struct
MAP MAP 是一组键-值对元组集合,使用数组表示法可以 访问数据。例如,如果某个列的数据类型是 MAP,其中键->值对是’first’->’John’和’last’->’Doe’,那么可以 通过字段名[‘last’]获取最后一个元素 map() 例如 map
ARRAY 数组是一组具有相同类型和名称的变量的集合。这些 变量称为数组的元素,每个数组元素都有一个编号,编号从 零开始。例如,数组值为[‘John’, ‘Doe’],那么第 2 个元素可以通过数组名[1]进行引用。 Array()例如 array

创建表的语句:

0: jdbc:hive2://hadoop100:10000> create table testCluster(name string, children map<string, int>, address struct<street:string, city:string>)
. . . . . . . . . . . . . . . .> row format delimited fields terminated by ','
. . . . . . . . . . . . . . . .> collection items terminated by '_'
. . . . . . . . . . . . . . . .> map keys terminated by':'
. . . . . . . . . . . . . . . .> lines terminated by '\n';

字段解释:

  • row format delimited fields terminated by ‘,’ – 列分隔符 collection
  • items terminated by ‘_’ --MAP STRUCT 和 ARRAY 的分隔符(数据分割符号) map keys
  • terminated by ‘:’ – MAP 中的 key 与 value 的分隔符
  • lines terminated by ‘\n’; – 行分隔符

这种使用方法也不常用,不是重点。

1.3 类型转化

1)隐式类型转换规则如下
(1)任何整数类型都可以隐式地转换为一个范围更广的类型,如 TINYINT 可以转换成
INT,INT 可以转换成 BIGINT。
(2)所有整数类型、FLOAT 和 STRING 类型都可以隐式地转换成 DOUBLE。
(3)TINYINT、SMALLINT、INT 都可以转换为 FLOAT。
(4)BOOLEAN 类型不可以转换为任何其它的类型。
2)可以使用 CAST 操作显示进行数据类型转换
例如 CAST(‘1’ AS INT)将把字符串’1’ 转换成整数 1;如果强制类型转换失败,如执行 CAST(‘X’ AS INT),表达式返回空值 NULL。

2、DDL数据定义

2.1 数据库

2.1.1 创建数据库

建表语句:

CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
  [COMMENT database_comment]
  [LOCATION hdfs_path]
  [MANAGEDLOCATION hdfs_path]
  [WITH DBPROPERTIES (property_name=property_value, ...)];

LOCATION 是指定外部表的存储路径,MANAGEDLOCATION 是指定管理表的存储路径(hive 4.0.0 才支持),官方建议默认就行,让所有的表都在一个根目录下。

create database if not exists db_hive comment "2021-10-21dbtest" location '/db_hive';

上述语句很好理解,执行完之后可以在HDFS上看到相应的目录已经建立了,然后再元数据中DBS已经有新建表的信息。
hive原理与实操(二):hive中数据定义(DDL)与数据管理(DML),初学者视角学hive。_第1张图片
hive原理与实操(二):hive中数据定义(DDL)与数据管理(DML),初学者视角学hive。_第2张图片

2.1.2 查询数据库

desc database db_hive;

查询结果与元数据中那个表格一样(见上图)
切换数据库:

use db_hive

怎么查看当前在使用哪个数据库呢?

select current_database();

2.1.3 修改数据库

alter database db_hive set dbproperties('createtime'='20001021');

2.1.4 删除数据库

通用语法:

如果数据库下有表,则不允许删除;如果要删除,后面加 CASCADE。RESTRICT 为默认值,默认不允许删除。

如果数据库下有表,则不允许删除;如果要删除,后面加 CASCADE。RESTRICT 为默认值,默认不允许删除。举个例子:

drop database if exists db_hive2;

2.2 表

2.2.1 内部表、外部表、分区表和分桶表简介

(1)首先介绍一下外部表和内部表(管理表)的区别和联系:

  • 外部表的数据由 hdfs 管理,而内部表的数据由 hive 管理。
  • 内部表数据存储的位置是hive.metastore.warehouse.dir(默认:/user/hive/warehouse),外部表数据的存储位置由自己制定(如果没有LOCATION,Hive将在HDFS上的/user/hive/warehouse文件夹下以外部表的表名创建一个文件夹,并将属于这个表的数据存放在这里);
  • 删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
  • 对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE table_name)

讲到外部表,那么日志场景用的会很多。通常服务器上会每时每刻产生日志,而这些日志会实时的发送到消息中间件,再通过 flume 等工具直接存储到 hdfs 上了,并没有 hive 什么事。但 hive 能把 hdfs 的文件映射成一张表,那么这种表就是外部表。外部表一般用的比较多。

(2)接下来介绍一下简单介绍一下分区表和分桶表:

1)为啥需要引入分区表?

引入分区表主要是为了更快的查询。从文件上来看,分区是 hdfs 的一个目录,可以指定多个分区,这样在插入数据的时候,hdfs 会产生多个目录。如果按照分区组织数据,查询数据的时候指定分区,底层直接返回该分区的数据,就会快很多。比如按照日期组织日志数据,就可以较快的查询出每天的日志。

2)为啥需要引入分桶表?

主要原因有两点:一是提高 join 查询的效率;二是利于抽样。从文件的角度来看,分桶表是根据数据的hash值,把数据存为不同的文件,也就是说向分桶表中插入数据的时候必然要执行一次MapReduce, 对于两个数据表,某两列都做了桶划分,可以使用map端的join高效的完成join(桶和桶之间的join,大大减少了join的次数)。对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的 mapper 知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取那个桶 (这只是右边表内存储数据的一小部分)即可进行连接。抽样也是如此,直接对每个桶进行抽样。

上面两个问题就可以建立对分区表和分桶表的简单印象,具体对比如下:

  • (1)从表现形式上:分区表是一个目录,分桶表是文件
  • (2)从创建语句上:
    • 分区表使用partitioned by 子句指定,以指定字段为伪列,需要指定字段类型;
    • 分桶表由clustered by 子句指定,指定字段为真实字段,需要指定桶的个数
  • (3)从数量上:分区表的分区个数可以增长,分桶表一旦指定,不能再增长
  • (4)从作用上:
    • 分区避免全表扫描,根据分区列查询指定目录提高查询速度
    • 分桶保存分桶查询结果的分桶结构(数据已经按照分桶字段进行了hash散列)。
    • 分桶表数据进行抽样和JOIN时可以提高MR程序效率。

2.2.1 创建表

从表创建而言,被 external 关键字修饰的就是外部表(external table),未被 external 修饰的表是管理表(managed table),分区表使用partitioned by 子句指定,分桶表由clustered by 子句指定。举个例子:

(1)创建管理表

create table if not exists student( id int, name string)
row format delimited fields terminated by '\t' 
stored as textfile
location '/user/hive/warehouse/student';

(2)创建外部表(external关键字)

  • 其中 row format delimited 表示定义格式
  • fields terminated by ‘’ 表示字段按 ''来分割
  • LINES TERMINATED BY ‘\n’ 行按回车符来分割,默认,一般不写
  • location ‘/user/hdfs/source/hive_test’ 表示这个外部表的数据时放在这个目录下面
CREATE EXTERNAL TABLE IF NOT EXISTS my_hive (id INT,name STRING)
row format delimited 
fields terminated by ','
LINES TERMINATED BY '\n'
stored as textfile 
location '/user/hdfs/source/hive_test' ;

(3)分区表使用partitioned by 子句指定,以指定字段为伪列,需要指定字段类型;

create table if not exists par_test(
 name string,
 nid int,
 phone string,
 ntime date
 )
 partitioned by (year string,month string) 
 row format delimited 
 fields terminated by "|"
 lines terminated by "\n"
 stored as textfile;

(4)分桶表由clustered by 子句指定,指定字段为真实字段,需要指定桶的个数,插入数据的时候,会把 sex 取 hash,并对2取模,放到2个桶里面去。

create table bck_student(
  id int,
  name string,
  sex string, 
  age int,
  department string
  ) 
  clustered by(sex) into 2 buckets 
  row format delimited 
  fields terminated  by ",";

上面四个小实例只是为了方便理解,详细的建表语句:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)] 
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] 
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
[ROW FORMAT row_format]
[STORED AS file_format] 
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)] 
[AS select_statement]

详细的解释:
(1)CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常; 用户可以用 IF NOT EXISTS 选项来忽略这个异常。
(2)EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实 际数据的路径(LOCATION),在删除表的时候,内部表的元数据和数据会被一起删除,而外 部表只删除元数据,不删除数据。
(3)COMMENT:为表和列添加注释。
(4)PARTITIONED BY 创建分区表
(5)CLUSTERED BY 创建分桶表
(6)SORTED BY 不常用,对桶中的一个或多个列另外排序
(7)ROW FORMAT:用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需 要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表 的具体的列的数据。SerDe 是 Serialize/Deserilize 的简称, hive 使用 Serde 进行行对象的序列与反序列化
(8)STORED AS 指定存储文件类型 常用的存储文件类型:SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
(9)LOCATION :指定表在 HDFS 上的存储位置。
(10)AS:后跟查询语句,根据查询结果创建表。
(11)LIKE 允许用户复制现有的表结构,但是不复制数据。

(5)根据已有的表建表
以目标查询结果来建表:

CREATE TABLE new_key_value_store
   AS
SELECT (key % 1024) new_key, concat(key, value) key_value_pair
FROM key_value_store
SORT BY new_key, key_value_pair;

以存在的表创建表:

CREATE TABLE empty_key_value_store
LIKE key_value_store;

(6)定义数据倾斜和字段值:
对于一个或多个列具有倾斜值的表,可以使用该特性提高性能。通过指定的值经常出现(数据倾斜),hive将这些分割成单独的文件(或目录的列表用桶装)。自动查询期间,考虑到这一事实,以便它可以跳过或者包含整个文件查询计算。

CREATE TABLE list_bucket_multiple (col1 STRING, col2 int, col3 STRING)
  SKEWED BY (col1, col2) ON (('s1',1), ('s3',3), ('s13',13), ('s78',78));

(7)根据指定的序列化与反序列化建表

  • 1,序列化是对象转化为字节序列的过程;
  • 2,反序列化是字节码恢复为对象的过程;

表数据行的序列化和反序列化大概过程如下:

  • HDFS 文件 ——> InputFileFormate ——> ——> 反序列化 ——> 数据行对象(Row object)
  • 数据行对象(Row object)——> 序列化 ——> ——> OutputFileFormate ——> HDFS 文件

在Hive的HQL语句中,select时将会用到序列化操作, insert 时会用到反序列化操作,下面是具体的操作过程。Hive创建表时,通过定义的SerDe或使用Hive内置的SerDe类型指定数据的序列化和反序列化方式。SerDe包括的内置类型:Avro、ORC、RegEx、Thrift、Parquet、CSV和JsonSerDe。这部分的内容有点像hadoop中写mapreduce程序中写序列化库的内容。

CREATE TABLE apachelog (
  host STRING,
  identity STRING,
  user STRING,
  time STRING,
  request STRING,
  status STRING,
  size STRING,
  referer STRING,
  agent STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
  "input.regex" = "([^]*) ([^]*) ([^]*) (-|\\[^\\]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\".*\") ([^ \"]*|\".*\"))?"
)
STORED AS TEXTFILE;

(8)创建临时表:临时表,表示在当前用户会话内才有效,数据全都存在用户临时目录中,一旦退出对话,表和数据都会被清除掉

CREATE TEMPORARY TABLE list_bucket_multiple (
  col1 STRING, 
  col2 int, 
  col3 STRING
);

2.2.2 修改表

(1)修改表名

alter table test rename to testRename;

(2)修改表属性

ALTER TABLE table_name SET TBLPROPERTIES ('comment' = new_comment);

(3)增加序列化与反序列化

ALTER TABLE apachelog SET SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES  (
  "input.regex" = "bduid\\[(.*)\\]uid\\[(\\d+)\\]"
)

(4)增加、修改和删除表分区
增加表分区:

ALTER TABLE page_view ADD PARTITION (dt='2008-08-08', country='us') location '/path/to/us/part080808'
                          PARTITION (dt='2008-08-09', country='us') location '/path/to/us/part080809';

删除表分区:

ALTER TABLE page_view DROP PARTITION (dt='2008-08-08', country='us') location '/path/to/us/part080808'
                          PARTITION (dt='2008-08-09', country='us') location '/path/to/us/part080809';

查看分区:

show partitions dept_partition;

查看分区表结构:

desc formatted dept_partition;

(5)修改字段名

-- 创建一个表
CREATE TABLE test_change (a int, b int, c int);
 
-- 修改列 a 的名字为 a1
ALTER TABLE test_change CHANGE a a1 INT;
 
-- 修改列 a1 的名字为 a2,类型变成 STRING,并放在 字段 b 后面
ALTER TABLE test_change CHANGE a1 a2 STRING AFTER b;
-- 修改后的结构为:  b int, a2 string, c int.
  
-- 修改列 c 的名字为 c1,并放在第一列
ALTER TABLE test_change CHANGE c c1 INT FIRST;
-- 修改后的结构为  c1 int, b int, a2 string.
  
-- 增加一列 a1
ALTER TABLE test_change CHANGE a1 a1 INT COMMENT 'this is column a1';

2.2.3 删除表

DROP TABLE [IF EXISTS] table_name [PURGE]

3、DML数据操作

3.1 数据导入

3.1.1 加载数据

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
 
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)

(1) filepath 可以是绝对路径,也可以是相对路径,也可以是 hdfs 路径;
(2) 如果指定了 LOCAL,则会从本地加载文件到目标地址;如果没有指定,则会把 filepath 的文件 移动 到目标表里去;
(3) 如果指定了 overwrite,则会先把目标表的内容清空,再把数据添加进去。如果没有指定,则会把数据添加到表中;
(4) 如果是分区表,则需要指定一个分区

3.1.2 插入数据

(1)insert语法

-- insert overwrite
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] 
select_statement1 FROM from_statement;

-- insert into
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] 
select_statement1 FROM from_statement;
  • insert into:以追加数据的方式插入到表或分区,原有数据不会删除
  • insert overwrite:会覆盖表中已存在的数据

上面挺好理解的,也存在multi insert:multi insert 可以将一张表的数据,写入到多张表中去。hive 只会读取一次表数据。

FROM src
INSERT OVERWRITE TABLE dest1 SELECT src.* WHERE src.key < 100
INSERT OVERWRITE TABLE dest2 SELECT src.key, src.value WHERE src.key >= 100 and src.key < 200
INSERT OVERWRITE TABLE dest3 PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 and src.key < 300
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;

3.2 数据导出

(1)Insert导出

INSERT OVERWRITE [LOCAL] DIRECTORY directory1
  [ROW FORMAT row_format] [STORED AS file_format] (Note: Only available starting with Hive 0.11.0)
  SELECT ... FROM ...
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/reg_3' SELECT a.* FROM events a;

(2)hadoop命令导出

dfs -get /user/hive/warehouse/student/student.txt
/opt/module/data/export/student3.txt;

(3)hive shell导出:查询结果重定向到本地文件中

bin/hive -e 'select * from default.student;' >
/opt/module/hive/data/export/student4.txt;

(4)export导出

export table default.student to 目录

export导出后可以直接导入,因为其自动生成了一个元数据目录

import table student2
from '/user/hive/warehouse/export/student';

数据查询会单出一篇文章来复习,这篇文章偏工具性一点,忘了就来查。贴个官网连接,写的详细又明白,不过是英文的。

你可能感兴趣的:(hadoop大数据,hive,hadoop,数据仓库,大数据,etl)