其他分享
首页 > 其他分享> > Hive-day3

Hive-day3

作者:互联网

Hive分区

 在大数据中,最常见的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,这样每次操作一个个小的文件就会很容易了,同样的道理,在hive当中也是支持这种思想的,就是我们可以把大的数据,按照每天或者每小时切分成一个个小的文件,这样去操作小的文件就会容易很多了。

 

假如现在我们公司一天产生3亿的数据量,那么为了方便管理和查询,就做以下的事情。

1)建立分区(可按照日期,部门等等具体业务分区)

2)分门别类的管理

 

为什么要分区(面试)?

避免全局扫描,加快查询速率

1.静态分区(SP)

静态分区(SP)static partition–partition by (字段 类型)

创建单分区表语法:

CREATE TABLE IF NOT EXISTS t_student (
sno int,
sname string
) partitioned by(grade int)
row format delimited fields terminated by ',';
--  分区的字段不要和表的字段相同。相同会报错error10035


1,xiaoyu01,1
2,xiaoyu02,1
3,xiaoyu03,1
4,xiaoyu04,1
5,xiaoyu05,1

6,xiaoyu06,2
7,xiaoyu07,2
8,xiaoyu08,2

9,xiaoyu09,3
10,xiaoyu10,3
11,xiaoyu11,3
12,xiaoyu12,3
13,xiaoyu13,3
14,xiaoyu14,3

15,xiaoyu15,3
16,xiaoyu16,4
17,xiaoyu17,4
18,xiaoyu18,4
19,xiaoyu19,4
20,xiaoyu20,4
21,xiaoyu21,4
-- 载入数据
-- 将相应年级一次导入
load data local inpath '/usr/local/soft/bigdata/j1.txt' into table t_student partition(grade=1);_student partition(grade=1);

-- 演示多拷贝一行上传,分区的列的值是分区的值,不是原来的值
在同一个文件中,后面数值是3但在4的分区里不会报错

静态多分区表语法:

CREATE TABLE IF NOT EXISTS t_teacher (
tno int,
tname string
) partitioned by(grade int,clazz int)
row format delimited fields terminated by ',';

--注意:前后两个分区的关系为父子关系,也就是grade文件夹下面有多个clazz子文件夹。
1,xiaoge01,1,1
2,xiaoge02,1,1

3,xiaoge03,1,2
4,xiaoge04,1,2

5,xiaoge05,1,3
6,xiaoge06,1,3

7,xiaoge07,2,1
8,xiaoge08,2,1

9,xiaoge09,2,2

--载入数据
load data local inpath '/usr/local/soft/bigdata/hivedata/teacher_1.txt' into table t_teacher partition(grade=1,clazz=1);

分区表查询

select * from t_student where grade = 1;

// 全表扫描,不推荐,效率低
select count(*) from students_pt1;

// 使用where条件进行分区裁剪,避免了全表扫描,效率高
select count(*) from students_pt1 where grade = 1;

// 也可以在where条件中使用非等值判断
select count(*) from students_pt1 where grade<3 1 and grade>=1;

查看分区

show partitions t_student;

添加分区

alter table t_student add partition (grade=5);

alter table t_student add partition (grade=5) location '指定数据文件的路径';从

删除分区

alter table t_student drop partition (grade=5);

 2.动态分区(DP)

 开启动态分区首先要在hive会话中设置如下的参数

# 表示开启动态分区
hive> set hive.exec.dynamic.partition=true;

# 表示动态分区模式:strict(需要配合静态分区一起使用)、nostrict
# strict: insert into table students_pt partition(dt='anhui',pt) select ......,pt from students;
hive> set hive.exec.dynamic.partition.mode=nonstrict;

===================以下是可选参数======================

# 表示支持的最大的分区数量为1000,可以根据业务自己调整
hive> set hive.exec.max.dynamic.partitions.pernode=1000;

 

 其余的参数详细配置如下

设置为true表示开启动态分区的功能(默认为false)
--hive.exec.dynamic.partition=true;

设置为nonstrict,表示允许所有分区都是动态的(默认为strict)
-- hive.exec.dynamic.partition.mode=nonstrict; 

每个mapper或reducer可以创建的最大动态分区个数(默认为100) 
比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错
--hive.exec.max.dynamic.partition.pernode=100; 

一个动态分区创建可以创建的最大动态分区个数(默认值1000)
--hive.exec.max.dynamic.partitions=1000;

全局可以创建的最大文件个数(默认值100000)
--hive.exec.max.created.files=100000; 

当有空分区产生时,是否抛出异常(默认false) 
-- hive.error.on.empty.partition=false;  

 

 案例1:动态插入学生年级班级信息

--创建分区表
CREATE TABLE IF NOT EXISTS t_student_d (
sno int,
sname string
) partitioned by (grade int,clazz int)
row format delimited fields terminated by ',';

--创建外部表
CREATE EXTERNAL TABLE IF NOT EXISTS t_student_e (
sno int,
sname string,
grade int,
clazz int
) 
row format delimited fields terminated by ','
location "/shujia/bigdata19/input/teachers";
数据:

1,xiaoyu01,1,1
2,xiaoyu02,1,1
3,xiaoyu03,1,1
4,xiaoyu04,1,2
5,xiaoyu05,1,2
6,xiaoyu06,2,3
7,xiaoyu07,2,3
8,xiaoyu08,2,3
9,xiaoyu09,3,3
10,xiaoyu10,3,3
11,xiaoyu11,3,3
12,xiaoyu12,3,4
13,xiaoyu13,3,4
14,xiaoyu14,3,4
15,xiaoyu15,3,4
16,xiaoyu16,4,4
17,xiaoyu17,4,4
18,xiaoyu18,4,5
19,xiaoyu19,4,5
20,xiaoyu20,4,5
21,xiaoyu21,4,5

 

 如果静态分区,插入数据必须指定分区的值;如果插入多次就会很麻烦,而且静态分区有可能会产生数据错误问题

-- 会报错 
insert overwrite table t_student_d partition (grade=1) select * from t_student_e where grade=1;

 

如果使用动态分区,动态分区会根据select的结果自动判断数据应该 load到哪个分区

insert overwrite table t_student_d partition (grade,clazz) select * from t_student_e;

优点:不用手动指定,自动会对数据进行分区

缺点:可能会出现数据倾斜

静态分区和动态分区的区别:

静态分区:先创建分区表,手动指定分区的值,将对应的数据加载到分区目录下

动态分区:先有一个包含了所有数值的原始表,然后创建分区表,将原始表的数据载入到分区表中,会自动根据数据列的值创建对应的分区

 Hive分桶

1.业务场景

数据分桶的适用场景:

  1. 分区提供了一个隔离数据和优化查询的便利方式,不过并非所有的数据都可形成合理的分区,尤其是需要确定合适大小的分区划分方式
  2. 不合理的数据分区划分方式可能导致有的分区数据过多,而某些分区没有什么数据的尴尬情况
  3. 分桶是将数据集分解为更容易管理的若干部分的另一种技术。
  4. 分桶就是将数据按照字段进行划分,可以将数据按照字段划分到多个文件当中去。

2.数据分桶原理

Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。

3.数据分桶优势

方便抽样

使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便

提高join查询效率

获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。

4.分桶实战

  1. 首先,分区和分桶是两个不同的概念,很多资料上说需要先分区在分桶,其实不然,分区是对数据进行划分,而分桶是对文件进行划分。
  2. 当我们的分区之后,最后的文件还是很大怎么办,就引入了分桶的概念。
  3. 将这个比较大的文件再分成若干个小文件进行存储,我们再去查询的时候,在这个小范围的文件中查询就会快很多。
  4. 对于hive中的每一张表、分区都可以进一步的进行分桶。
  5. 当然,分桶不是说将文件随机进行切分存储,而是有规律的进行存储。在看完下面的例子后进行解释,现在干巴巴的解释也不太好理解。它是由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。
  6. 创建顺序和分区一样,创建的方式不一样。

首先我们需要开启分桶的支持

(依然十分重要,不然无法进行分桶操作!!!!)
set hive.enforce.bucketing=true; 

数据准备

1,tom,11
2,cat,22
3,dog,33
4,hive,44
5,hbase,55
6,mr,66
7,alice,77
8,scala,88

创建一个普通的表

create table psn31
(
id int,
name string,
age int
)
row format delimited
fields terminated by ',';

将数据load到这张表中

load data local inpath '文件在Linux上的绝对路径' into table psn31;

创建分桶表

create table psn_bucket
(
id int,
name string,
age int
)
clustered by(age) into 4 buckets
row format delimited
fields terminated by ',';

将数据insert到表psn_bucket中

(注意:这里和分区表插入数据有所区别,分区表需要select 和指定分区,而分桶则不需要)

insert into psn_bucket select id,name,age from psn31;

在HDFS上查看数据

查询数据

我们在linux中使用Hadoop的命令查看一下(与我们猜想的顺序一致)

hadoop fs -cat /user/hive/warehouse/bigdata.db/psn_bucket/*

 

这里设置的桶的个数是4 数据按照 年龄%4 进行放桶(文件)

11%4 == 3 -----> 000003_0

22%4 == 2 -----> 000002_0

33%4 == 1 -----> 000001_0

44%4 == 0 -----> 000000_0

...以此类推

在hive中进行查询

-- tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y)
-- 分桶语句中的分母表示的是数据将会被散列的桶的个数,分子表示将会选择的桶的个数。

-- x表示从哪个bucket开始抽取。
-- 例如,table总bucket数为32,tablesample(bucket 2 out of 2)
-- 表示总共抽取(2/2=)1个bucket的数据,分别为第2个bucket和第(2+2=)4个bucket的数据
-- y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。
-- 例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据

select * from psn_bucket tablesample(bucket 3 out of 2);
随机取值(设置因子,桶的个数/因子)
这里就是取2号桶和4号桶,取2个

select * from psn_bucket tablesample(bucket 2 out of 4);
随机取值(设置因子,桶的个数/因子)
这里就是取2号桶,取一个

select * from psn_bucket tablesample(bucket 2 out of 8);
随机取值(设置倍数,倍数/桶的个数)
这里就是取2号桶 1/2个数据
取出来是一条数据

Hive  JDBC

启动hiveserver2

hive --service hiveserver2 &
或者
hiveserver2 &

新建maven项目并添加两个依赖

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc -->
    <dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-jdbc</artifactId>
        <version>1.2.1</version>
    </dependency>

编写JDBC代码

import java.sql.*;

public class HiveJDBC {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("org.apache.hive.jdbc.HiveDriver");
        Connection conn = DriverManager.getConnection("jdbc:hive2://master:10000/bigdata17");
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery("select * from students limit 10");
        while (rs.next()) {
            int id = rs.getInt(1);
            String name = rs.getString(2);
            int age = rs.getInt(3);
            String gender = rs.getString(4);
            String clazz = rs.getString(5);
            System.out.println(id + "," + name + "," + age + "," + gender + "," + clazz);
        }
        rs.close();
        stat.close();
        conn.close();
    }
}

Hive查询语法(DQL)

SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT [offset,] rows]

1.全局排序

select * from 表名 order by 字段名1[,别名2...];

2.局部排序

set mapreduce.job.reduce=3;
set mapred.reduce.tasks=3;

查看reduce个数

set mapreduce.job.reduce;

排序

select * from 表名 distribute by 字段名[,字段名...];

3.分区排序

设置reduce个数

set mapreduce.job.reduce=7;

 

排序

select * from 表名 distribute by 字段名[,字段名...];

 

4.分区并排序

select * from 表名 sort cluster by 字段名[,字段名...];
select * from 表名 distribute by 字段名[,字段名...] sort by 字段名[,字段名...];

hive几种分区的区别

distribute by name 后面分区是13和24;

 必须经过sort by

5.Hive内置函数

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
-- 1.查看系统自带函数
show functions;
-- 2.显示自带的函数的用法
desc function upper;
-- 3.详细显示自带的函数的用法
desc function extended upper;

1.内置函数分类

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:--,分区,bucket,day3,hive,Hive,数据,select
来源: https://www.cnblogs.com/wqy1027/p/16659685.html