大数据高级开发工程师——Hive学习笔记(2)

文章目录

  • Hive提高篇
    • Hive的使用
      • Hive的分桶表
        • 1. 分桶表的原理
        • 2. 分桶表的作用
        • 3. 案例演示
      • Hive数据导入
        • 1. 直接向表中插入数据(强烈不推荐使用)
        • 2. 通过load加载数据(必须掌握)
        • 3. 通过查询加载数据(必须掌握)
        • 4. 查询语句中创建表并加载数据(as select)
        • 5. 创建表时指定location
        • 6. export导出与import 导入 hive表数据(内部表操作)
      • Hive数据导出
        • 1. insert 导出
        • 2. Hive Shell 命令导出 (需要在linux终端执行)
        • 3 export导出到HDFS上
      • Hive的静态分区和动态分区
        • 1. 静态分区
        • 2. 动态分区
      • Hive的查询语法
        • 1. 基本查询
        • 2. 分组
        • 3. join语句
        • 4. 排序
      • Hive表的数据压缩
        • 1. 数据压缩对比
        • 2. 压缩配置参数
        • 3. 开启Map输出阶段压缩
        • 4. 开启Reduce输出阶段压缩
      • Hive表的文件存储格式
        • 1. 列式存储和行式存储
        • 2. TEXTFILE格式
        • 3. ORC格式
        • 4. PARQUET格式 (impala)
        • 5. 主流文件存储格式对比实验
          • TextFile
          • ORC
          • Parquet
          • 存储文件的查询速度测试
      • 存储和压缩结合
        • 1. 创建一个非压缩的的ORC存储方式
        • 2. 创建一个SNAPPY压缩的ORC存储方式
        • 3. 企业实战
          • 通过MultiDelimitSerDe 解决多字符分割场景
          • 通过RegexSerDe 解决多字符分割场景

Hive提高篇

Hive的使用

Hive的分桶表

大数据高级开发工程师——Hive学习笔记(2)_第1张图片

1. 分桶表的原理

  • 分桶是相对分区进行更细粒度的划分,Hive表或分区表可进一步的分桶
  • 分桶将整个数据内容按照某列取hash值,对桶的个数取模的方式决定该条记录存放在哪个桶当中;具有相同hash值的数据进入到同一个文件中
  • 比如按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。
    • 取模结果为0的数据记录存放到一个文件
    • 取模结果为1的数据记录存放到一个文件
    • 取模结果为2的数据记录存放到一个文件

2. 分桶表的作用

  • 取样sampling更高效。没有分桶的话需要扫描整个数据集。
  • 提升某些查询操作效率,例如map side join。

3. 案例演示

  • 在创建分桶表之前要执行的命令
# 开启对分桶表的支持
set hive.enforce.bucketing=true;
# 设置与桶相同的reduce个数(默认只有一个reduce)
set mapreduce.job.reduces=4;
  • 创建分桶表:
use myhive;
create table user_buckets_demo(id int, name string)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
-- 创建普通表
create table user_demo(id int, name string)
row format delimited fields terminated by '\t';
  • 数据文件 user_bucket.txt
1	anzhulababy1
2	anzhulababy2
3	anzhulababy3
4	anzhulababy4
5	anzhulababy5
6	anzhulababy6
7	anzhulababy7
8	anzhulababy8
9	anzhulababy9
10	anzhulababy10
  • 加载数据:
# 加载数据到普通表 user_demo 中
load data local inpath '/bigdata/install/hivedatas/user_bucket.txt' overwrite into table user_demo;
# 加载数据到桶表user_buckets_demo中
insert into table user_buckets_demo select * from user_demo;

大数据高级开发工程师——Hive学习笔记(2)_第2张图片

  • hdfs 上查看表的数据目录:

大数据高级开发工程师——Hive学习笔记(2)_第3张图片

hive3.x版本之后, 可以直接向分桶表中load数据即可, 不需要通过insert … select 语句像分桶表插入数据的方式来进行分桶
注意: 希望load能够直接分桶, 需要从hdfs上load文件, 不能从本地load

load data inpath '/user/hive/warehouse/myhive.db/user_demo' overwrite into table myhive.user_buckets_demo;

Hive数据导入

1. 直接向表中插入数据(强烈不推荐使用)

hive (myhive)> create table score3 like score;
hive (myhive)> insert into table score3 partition(month = '201807') values('001', '002', '100');

2. 通过load加载数据(必须掌握)

  • 语法:
load data [local] inpath 'dataPath' [overwrite] into table student [partition(partcol1=val1,)]; 
  • 通过load方式加载数据
hive (myhive)> load data local inpath '/bigdata/install/hivedatas/score.csv' into table score partition(month='201806');

3. 通过查询加载数据(必须掌握)

  • 语法:官网地址
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
  • 例子:
hive (myhive)> create table score5 like score;
hive (myhive)> insert overwrite table score5 partition(month = '201806') select s_id,c_id,s_score from score;

4. 查询语句中创建表并加载数据(as select)

  • 将查询的结果保存到一张表当中去
hive (myhive)> create table score6 as select * from score;

5. 创建表时指定location

  • 创建表,并指定在hdfs上的位置
hive (myhive)> create external table score7 (s_id string,c_id string,s_score int) row format delimited fields terminated by '\t' location '/myscore7';
  • 上传数据到hdfs上,我们也可以直接在hive客户端下面通过dfs命令来进行操作hdfs的数据
hive (myhive)> dfs -mkdir -p /myscore7;
hive (myhive)> dfs -put /bigdata/install/hivedatas/score.csv /myscore7;
  • 查询数据
hive (myhive)> select * from score7;

6. export导出与import 导入 hive表数据(内部表操作)

hive (myhive)> create table teacher2 like teacher;
-- 导出到hdfs路径
hive (myhive)> export table teacher to  '/user/teacher';
hive (myhive)> import table teacher2 from '/user/teacher';

Hive数据导出

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 '/bigdata/install/hivedatas/stu1' select * from stu1;
  • 将查询的结果格式化导出到本地
insert overwrite local directory '/bigdata/install/hivedatas/stu1' row format delimited fields terminated by ',' select * from stu1;
  • 将查询的结果导出到HDFS上==(没有local)==
insert overwrite directory '/bigdata/install/hivedatas/stu' row format delimited fields terminated by  ','  select * from stu;

2. Hive Shell 命令导出 (需要在linux终端执行)

  • 基本语法:
hive -e "sql语句" >   file
hive -f  sql文件   >    file
  • 在linux命令行中,运行如下命令,导出 myhive.stu 表的数据到本地磁盘文
hive -e 'select * from myhive.stu;' > /bigdata/install/hivedatas/student1.txt;

3 export导出到HDFS上

export table  myhive.stu to '/bigdata/install/hivedatas/stuexport';

Hive的静态分区和动态分区

1. 静态分区

  • 表的分区字段的值需要开发人员手动给定
  • 数据文件 order.txt
10001	100	2019-03-02
10002	200	2019-03-02
10003	300	2019-03-02
10004	400	2019-03-03
10005	500	2019-03-03
10006	600	2019-03-03
10007	700	2019-03-04
10008	800	2019-03-04
10009	900	2019-03-04
  • 创建分区表、加载数据、查询结果
use myhive;
-- 创建分区表
create table order_partition(
order_number string,
order_price  double,
order_time string
)
partitioned BY(month string)
row format delimited fields terminated by '\t';
-- 加载数据
load data local inpath '/bigdata/install/hivedatas/order.txt' overwrite into table order_partition partition(month='2019-03');
-- 查询结果
hive (myhive)> select * from order_partition where month='2019-03';
OK
order_partition.order_number	order_partition.order_price	order_partition.order_time	order_partition.month
10001	100.0	2019-03-02	2019-03
10002	200.0	2019-03-02	2019-03
10003	300.0	2019-03-02	2019-03
10004	400.0	2019-03-03	2019-03
10005	500.0	2019-03-03	2019-03
10006	600.0	2019-03-03	2019-03
10007	700.0	2019-03-04	2019-03
10008	800.0	2019-03-04	2019-03
10009	900.0	2019-03-04	2019-03
Time taken: 2.511 seconds, Fetched: 9 row(s)

2. 动态分区

  • 按照需求实现把数据自动导入到表的相应分区中,不需要手动指定分区字段的值
  • 需求:根据分区字段不同的值,自动将数据导入到分区表不同的分区中
  • 数据文件 order_partition.txt
10001	100	2019-03-02
10002	200	2019-03-02
10003	300	2019-03-02
10004	400	2019-03-03
10005	500	2019-03-03
10006	600	2019-03-03
10007	700	2019-03-04
10008	800	2019-03-04
10009	900	2019-03-04
  • 创建分区表、加载数据、查询结果
-- 创建普通表
create table t_order(
    order_number string,
    order_price  double, 
    order_time   string
)row format delimited fields terminated by '\t';
-- 创建目标分区表
create table order_dynamic_partition(
    order_number string,
    order_price  double    
)partitioned BY(order_time string)
row format delimited fields terminated by '\t';
-- 向普通表t_order加载数据
load data local inpath '/bigdata/install/hivedatas/order_partition.txt' overwrite into table t_order;
-- 动态加载数据到分区表中
-- 要想进行动态分区,需要设置参数
-- 开启动态分区功能
hive> set hive.exec.dynamic.partition=true; 
-- 设置hive为非严格模式
hive> set hive.exec.dynamic.partition.mode=nonstrict; 
hive> insert into table order_dynamic_partition partition(order_time) select order_number, order_price, order_time from t_order;
-- 查询结果
hive (myhive)> show partitions order_dynamic_partition;
OK
partition
order_time=2019-03-02
order_time=2019-03-03
order_time=2019-03-04
Time taken: 0.154 seconds, Fetched: 3 row(s)

hive3.x之后, 可以直接通过load的方式导入hdfs上的文件完成动态分区, 并且不需要做任何属性设置, 动态分区会根据最后一个字段来进行分区

load data inpath '/user/hive/warehouse/myhive.db/t_order' overwrite into table myhive.order_dynamic_partition;

Hive的查询语法

1. 基本查询

  • SQL 语言大小写不敏感,SQL 可以写在一行或者多行
  • 关键字不能被缩写也不能分行,各子句一般要分行写,使用缩进提高语句的可读性
-- 全表查询
select * from stu;
-- 特定列查询
select id, name from stu;
-- 列起别名
select id, name as stuName from stu;

-- 求总行数(count)
select count(*) from stu;
-- 求分数的最大值(max)
select max(s_score) from score;
-- 求分数的最小值(min)
select min(s_score) from score;
-- 求分数的总和(sum)
select sum(s_score) from score;
-- 求分数的平均值(avg)
select avg(s_score) from score;

-- limit 语句
select  * from score limit 5;
-- where 语句
select * from score where s_score > 60;
  • 算术运算符
运算符 描述
A+B A和B 相加
A-B A减去B
A*B A和B 相乘
A/B A除以B
A%B A对B取余
A&B A和B按位取与
A|B A和B按位取或
A^B A和B按位取异或
~A A按位取反
  • 比较运算符
操作符 支持的数据类型 描述
A=B 基本数据类型 如果A等于B则返回true,反之返回false
A<=>B 基本数据类型 如果A和B都为NULL,则返回true,其他的和等号(=)操作符的结果一致,如果任一为NULL则结果为NULL
A<>B, A!=B 基本数据类型 A或者B为NULL则返回NULL;如果A不等于B,则返回true,反之返回false
A 基本数据类型 A或者B为NULL,则返回NULL;如果A小于B,则返回true,反之返回false
A<=B 基本数据类型 A或者B为NULL,则返回NULL;如果A小于等于B,则返回true,反之返回false
A>B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于B,则返回true,反之返回false
A>=B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于等于B,则返回true,反之返回false
A [NOT] BETWEEN B AND C 基本数据类型 如果A,B或者C任一为NULL,则结果为NULL。如果A的值大于等于B而且小于或等于C,则结果为true,反之为false。如果使用NOT关键字则可达到相反的效果。
A IS NULL 所有数据类型 如果A等于NULL,则返回true,反之返回false
A IS NOT NULL 所有数据类型 如果A不等于NULL,则返回true,反之返回false
IN(数值1, 数值2) 所有数据类型 使用 IN运算显示列表中的值
A [NOT] LIKE B STRING 类型 B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回true;反之返回false。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。like不是正则,而是通配符
A RLIKE B, A REGEXP B STRING 类型 B是一个正则表达式,如果A与其匹配,则返回true;反之返回false。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。
  • 逻辑运算符
操作符 操作 描述
A AND B 逻辑并 如果A和B都是true则为true,否则false
A OR B 逻辑或 如果A或B或两者都是true则为true,否则false
NOT A 逻辑否 如果A为false则为true,否则false

2. 分组

-- group by语句:通常会和==聚合函数==一起使用,按照一个或者多个列对结果进行分组,然后对每个组执行聚合操作
-- 计算每个学生的平均分数
select s_id, avg(s_score) from score group by s_id;
-- 计算每个学生最高的分数
select s_id, max(s_score) from score group by s_id;

-- having 语句
-- where针对==表中的列发挥作用==,查询数据;==having针对查询结果中的列==发挥作用,筛选数据
-- where后面==不能写聚合函数==,而having后面可以==使用聚合函数==
-- having只用于group by分组统计语句
-- 求每个学生的平均分数
select s_id, avg(s_score) from score group by s_id;  
-- 求每个学生平均分数大于60的人
select s_id, avg(s_score) as avgScore from score group by s_id having avgScore > 60;
-- 等价于
select s_id, avg(s_score) as avgScore from score group by s_id having avg(s_score) > 60;

3. join语句

  • Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接
  • 等值 join
-- 根据学生和成绩表,查询学生姓名对应的成绩
select * from stu left join score on stu.id = score.s_id;

-- 合并老师与课程表
-- hive当中创建course表并加载数据
create table course (c_id string, c_name string, t_id string) 
row format delimited fields terminated by '\t';

load data local inpath '/bigdata/install/hivedatas/course.csv' overwrite into table course;

select * from teacher t join course c on t.t_id = c.t_id;
  • 内连接 inner join:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
select * from teacher t inner join course c on t.t_id = c.t_id;
  • 左外连接 left outer join:join操作符左边表中符合where子句的所有记录将会被返回,右边表的指定字段没有符合条件的值的话,那么就使用null值替代。
-- 查询老师对应的课程
select * from teacher t left outer join course c on t.t_id = c.t_id;
  • 右外连接 right outer join
select * from teacher t right outer join course c on t.t_id = c.t_id;
  • 满外连接 full outer join:将会返回所有表中符合where语句条件的所有记录,如果任一表的指定字段没有符合条件的值的话,那么就使用null值替代。
select * from teacher t full outer join course c on t.t_id = c.t_id;
  • 多表连接:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
-- 多表连接查询,查询商品对应的品牌和类别信息
select * from products p
left join brands b on p.brand_id = b.id 
left join categorys c on p.category_id = c.id;

4. 排序

  • 官网文档

  • order by 全局排序:只有一个reduce,使用 ORDER BY 子句排序

  • asc ( ascend) 升序 (默认)、desc (descend) 降序

-- 查询学生的成绩,并按照分数降序排列
select * from score s order by s_score desc;

s.s_id	s.c_id	s.s_score	s.month
01	03	99	201806
07	03	98	201806
01	02	90	201806
07	02	89	201806
05	02	87	201806
03	03	80	201806
03	02	80	201806
03	01	80	201806
02	03	80	201806
01	01	80	201806
05	01	76	201806
02	01	70	201806
02	02	60	201806
04	01	50	201806
06	03	34	201806
06	01	31	201806
04	02	30	201806
04	03	20	201806
  • 按照别名排序
select s_id, avg(s_score) avgscore from score group by s_id order by avgscore desc;

s_id	avgscore
07	93.5
01	89.66666666666667
05	81.5
03	80.0
02	70.0
04	33.333333333333336
06	32.5
  • 每个MapReduce内部排序(Sort By)局部排序:每个reducer内部有序排序(局部有序),对全局结果集来说并非全局有序。
-- 设置reduce个数
set mapreduce.job.reduces=3;
-- 查看reduce的个数
set mapreduce.job.reduces;
-- 查询成绩按照成绩降序排列
select * from score s sort by s.s_score;
-- 将查询结果导入到文件中(按照成绩降序排列)
insert overwrite local directory '/bigdata/install/hivedatas/sort' select * from score s sort by s.s_score;
  • distribute by 分区排序:类似MR中partition,采集hash算法,在map端将查询的结果中hash值相同的结果分发到对应的reduce文件中
    • 结合sort by使用;
    • Hive要求 distribute by 语句要写在 sort by 语句之前。
-- 先按照学生 sid 进行分区,再按照学生成绩进行排序
set mapreduce.job.reduces=3;
-- 通过distribute by  进行数据的分区,,将不同的sid 划分到对应的reduce当中去
insert overwrite local directory '/bigdata/install/hivedatas/distribute' select * from score distribute by s_id sort by s_score;
  • cluster by:当distribute by和sort by字段相同时,可以使用cluster by方式代替
    • 除了distribute by 的功能外,还会对该字段进行排序,所以cluster by s_score = distribute by s_score + sort by s_score
--以下两种写法等价
insert overwrite local directory '/bigdata/install/hivedatas/distribute_sort' select * from score distribute by s_score sort by s_score;

insert overwrite local directory '/bigdata/install/hivedatas/cluster' select * from score  cluster by s_score; 

Hive表的数据压缩

1. 数据压缩对比

  • 压缩模式评价:

    • 压缩比:压缩比越高,压缩后文件越小,所以压缩比越高越好
    • 压缩时间:越快越好
    • 是否可分割:可以分割的格式允许单一文件由多个Mapper程序处理,可以更好的并行化
  • 常见压缩格式

压缩方式 压缩比 压缩速度 解压缩速度 是否可分割
gzip 13.4% 21 MB/s 118 MB/s
bzip2 13.2% 2.4MB/s 9.5MB/s
lzo 20.5% 135 MB/s 410 MB/s
snappy 22.2% 172 MB/s 409 MB/s
  • Hadoop编/解码器方式
压缩格式 对应的编码/解码器
DEFLATE org.apache.hadoop.io.compress.DefaultCodec
Gzip org.apache.hadoop.io.compress.GzipCodec
BZip2 org.apache.hadoop.io.compress.BZip2Codec
LZO com.hadoop.compress.lzo.LzopCodec
Snappy org.apache.hadoop.io.compress.SnappyCodec
  • 压缩性能的比较
压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度
gzip 8.3GB 1.8GB 17.5MB/s 58MB/s
bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s
LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s
  • Snappy

2. 压缩配置参数

  • 要在Hadoop中启用压缩,可以配置如下参数(mapred-site.xml文件中):
参数 取值 阶段 建议
io.compression.codecs(在core-site.xml中配置) org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec, org.apache.hadoop.io.compress.Lz4Codec 输入压缩 Hadoop使用文件扩展名判断是否支持某种编解码器
mapreduce.map.output.compress true mapper输出 这个参数设为true启用压缩
mapreduce.map.output.compress.codec org.apache.hadoop.io.compress.DefaultCodec mapper输出 使用LZO、LZ4或snappy编解码器在此阶段压缩数据
mapreduce.output.fileoutputformat.compress true reducer输出 这个参数设为true启用压缩
mapreduce.output.fileoutputformat.compress.codec org.apache.hadoop.io.compress. DefaultCodec reducer输出 使用标准工具或者编解码器,如gzip和bzip2
mapreduce.output.fileoutputformat.compress.type NONE|RECORD reducer输出 SequenceFile输出使用的压缩类型:NONE和BLOCK

3. 开启Map输出阶段压缩

  • 开启map输出阶段压缩可以减少job中map和Reduce task间数据传输量。具体配置如下:
-- hql语句可能被转换成多个job,如job1的结果作为job2的输入...开启job间结果数据的压缩功能;默认false
hive (default)> set hive.exec.compress.intermediate=true;

-- 开启mapreduce中map输出压缩功能;默认false
hive (default)> set mapreduce.map.output.compress=true;

-- 设置mapreduce中map输出数据的压缩方式;默认DefaultCodec
hive (default)> set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;

-- 执行查询语句
hive (default)> select count(1) from score;

4. 开启Reduce输出阶段压缩

  • 当Hive将输出写入到表中时,输出内容同样可以进行压缩。属性 hive.exec.compress.output 控制着这个功能。用户可能需要保持默认设置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为true,来开启输出结果压缩功能。
-- 开启hive最终输出数据的压缩功能;默认false
hive (default)>set hive.exec.compress.output=true;

-- 开启mapreduce最终输出数据压缩;默认false
hive (default)>set mapreduce.output.fileoutputformat.compress=true;

-- 设置mapreduce最终数据输出压缩方式;默认DefaultCodec
hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;

-- 设置mapreduce最终数据输出压缩为块压缩;默认RECORD
hive (default)>set mapreduce.output.fileoutputformat.compress.type=BLOCK;

-- 测试一下输出结果是否是压缩文件
insert overwrite local directory '/bigdata/install/hivedatas/snappy' 
select * from teacher;

Hive表的文件存储格式

  • Hive支持的存储数据的格式主要有:TEXTFILE(行式存储) 、SEQUENCEFILE(行式存储)、ORC(列式存储)、PARQUET(列式存储)。

1. 列式存储和行式存储

大数据高级开发工程师——Hive学习笔记(2)_第4张图片

  • 上图左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
  • **行存储的特点:**查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
  • 列存储的特点:
    • 因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;
    • 每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。 select 某些字段效率更高。
  • TEXTFILE和SEQUENCEFILE的存储格式都是基于行存储的,ORC和PARQUET是基于列式存储的。

2. TEXTFILE格式

  • 默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用gzip方式,hive不会对数据进行切分,从而无法对数据进行并行操作。

3. ORC格式

  • Orc (Optimized Row Columnar)是hive 0.11版里引入的新的存储格式。
  • 可以看到每个Orc文件由1个或多个stripe组成,每个stripe250MB大小,这个Stripe实际相当于RowGroup概念,不过大小由4MB->250MB,这样能提升顺序读的吞吐率。每个Stripe里有三部分组成,分别是 Index Data、Row Data、Stripe Footer:

大数据高级开发工程师——Hive学习笔记(2)_第5张图片

  • 一个orc文件可以分为若干个Stripe,一个stripe可以分为三个部分:
    • IndexData:某些列的索引数据。一个轻量级的index,默认是每隔1W行做一个索引。这里做的索引只是记录某行的各字段在Row Data中的offset。
    • RowData:真正的数据存储。存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个Stream来存储。
    • StripFooter:存的是各个stripe的元数据信息。
  • 每个文件有一个File Footer,这里面存的是每个Stripe的行数,每个Column的数据类型信息等。
  • 每个文件的尾部是一个PostScript,这里面记录了整个文件的压缩类型以及FileFooter的长度信息等。在读取文件时,会seek到文件尾部读PostScript,从里面解析到File Footer长度,再读FileFooter,从里面解析到各个Stripe信息,再读各个Stripe,即从后往前读

4. PARQUET格式 (impala)

  • Parquet是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。
  • Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
  • 通常情况下,在存储Parquet数据的时候会按照Block大小设置行组的大小,由于一般情况下每一个Mapper任务处理数据的最小单位是一个Block,这样可以把每一个行组由一个Mapper任务处理,增大任务执行并行度。Parquet文件的格式如下图所示。

大数据高级开发工程师——Hive学习笔记(2)_第6张图片

  • 上图展示了一个Parquet文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的Magic Code,用于校验它是否是一个Parquet文件,Footer length记录了文件元数据的大小,通过该值和文件长度可以计算出元数据的偏移量,文件的元数据中包括每一个行组的元数据信息和该文件存储数据的Schema信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在Parquet中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字典页,索引页用来存储当前行组下该列的索引,目前Parquet中还不支持索引页。

5. 主流文件存储格式对比实验

  • 从存储文件的压缩比和查询速度两个角度对比。
  • 测试数据:https://download.csdn.net/download/yangwei234/58301049
TextFile
use myhive;
-- 创建表,存储数据格式为TEXTFILE
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;

-- 向表中加载数据
load data local inpath '/bigdata/install/hivedatas/log.data' into table log_text;

-- 查看表中数据大小
dfs -du -h /user/hive/warehouse/myhive.db/log_text;

大数据高级开发工程师——Hive学习笔记(2)_第7张图片

ORC
-- 创建表,存储数据格式为ORC
create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc ;

-- 向表中加载数据
insert into table log_orc select * from log_text ;

-- 查看表中数据大小
dfs -du -h /user/hive/warehouse/myhive.db/log_orc;

大数据高级开发工程师——Hive学习笔记(2)_第8张图片

  • orc这种存储格式,默认使用了zlib压缩方式来对数据进行压缩,所以数据会变成了2.8M,非常小
Parquet
-- 创建表,存储数据格式为parquet
create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS PARQUET ;  

-- 向表中加载数据
insert into table log_parquet select * from log_text ;

-- 查看表中数据大小
dfs -du -h /user/hive/warehouse/myhive.db/log_parquet;

大数据高级开发工程师——Hive学习笔记(2)_第9张图片

  • 结论:存储文件的压缩比
ORC >  Parquet >  textFile
存储文件的查询速度测试
select count(*) from log_text;
select count(*) from log_orc;
select count(*) from log_parquet;

大数据高级开发工程师——Hive学习笔记(2)_第10张图片

  • 存储文件的查询速度总结:
Parquet > ORC > TextFile

存储和压缩结合

  • ORC存储方式的压缩官网资料:
Key Default Notes
orc.compress ZLIB high level compression (one of NONE, ZLIB, SNAPPY)
orc.compress.size 262,144 number of bytes in each compression chunk;256kB
orc.stripe.size 67,108,864 number of bytes in each stripe
orc.row.index.stride 10,000 number of rows between index entries (must be >= 1000)
orc.create.index true whether to create row indexes
orc.bloom.filter.columns “” comma separated list of column names for which bloom filter should be created
orc.bloom.filter.fpp 0.05 false positive probability for bloom filter (must >0.0 and <1.0)

1. 创建一个非压缩的的ORC存储方式

-- 建表语句
create table log_orc_none(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="NONE");

-- 插入数据
insert into table log_orc_none select * from log_text ;

-- 查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_none;

大数据高级开发工程师——Hive学习笔记(2)_第11张图片

2. 创建一个SNAPPY压缩的ORC存储方式

-- 建表语句
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");

-- 插入数据
insert into table log_orc_snappy select * from log_text ;

-- 查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_snappy ;

大数据高级开发工程师——Hive学习笔记(2)_第12张图片- 上一节中默认创建的ORC存储方式,导入数据后的大小为

2.8 M  8.3 M  /user/hive/warehouse/myhive.db/log_orc/000000_0
  • 比Snappy压缩的还小:原因是orc存储文件默认采用ZLIB压缩,比snappy压缩的小。
  • 存储方式和压缩总结:在实际的项目开发当中,hive表的数据存储格式一般选择 orc 或 parquet,压缩方式一般选择snappy

3. 企业实战

通过MultiDelimitSerDe 解决多字符分割场景
  • 官网建表语法参考
  • MultiDelimitSerDe参考
  • 测试数据文件 t1.txt
1##xiaoming
2##xiaowang
3##xiaozhang
-- 创建表
create  table t1 (id String, name string)
row format serde 'org.apache.hadoop.hive.contrib.serde2.MultiDelimitSerDe'
WITH SERDEPROPERTIES ("field.delim"="##");

-- 加载数据
load data local inpath '/bigdata/install/hivedatas/t1.txt' into table t1;

-- 查询数据
select * from t1;
+--------+------------+--+
| t1.id  |  t1.name   |
+--------+------------+--+
| 1      | xiaoming   |
| 2      | xiaowang   |
| 3      | xiaozhang  |
+--------+------------+--+

大数据高级开发工程师——Hive学习笔记(2)_第13张图片

通过RegexSerDe 解决多字符分割场景
  • 官网手册参考
-- 创建表
create  table t2(id int, name string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ("input.regex" = "^(.*)\\#\\#(.*)$");

-- 加载数据
load data local inpath '/bigdata/install/hivedatas/t1.txt' into table t2;

-- 查询数据
select * from t2;
+--------+------------+--+
| t2.id  |  t2.name   |
+--------+------------+--+
| 1      | xiaoming   |
| 2      | xiaowang   |
| 3      | xiaozhang  |
+--------+------------+--+

大数据高级开发工程师——Hive学习笔记(2)_第14张图片

你可能感兴趣的:(大数据,hive,big,data,hadoop,分区表,数据仓库)