《MY大数据开发笔记》----hive知识点总结

hive的作用:hive最初的设计目的是为了给哪些精通sql但是不熟悉Hadoop的分析师,用来分析大规模的结构化的数据文件而设计的。

首先最重要的一点:

hive的使用和关系型数据库的使用方式类似(类sql语句),那我们为什么不使用关系型数据库而使用hive?

1.hive能分析超大数据规模的数据。

2.hive用于分析存储在文件中的结构化的数据。而关系型数据库不能。

所以hive最初的设计目的是:给哪些精通sql但是编码不熟练。而要分析的结构化的数据存储于大规模的文件中。在hive出现之前。是用MR来进行统计和分析。但是对这些存储文件中的结构化的数据。MR都类似。分析的统计最终数据也类似于关系型数据库中的手法。所以索性就将这些MR统一封装。成一个HQL语句。在调用HQL语句分析这些数据时,转换成MR。

 

 

一:hive提供的服务

输入hive --service help。弹出hive提供的服务列表。在这里主要介绍常用的几个服务。 cli ,hiveserver,hwi,jar

[s201 ~]$ hive --service help
Usage ./hive <parameters> --service serviceName <service parameters>
Service List: 
beeline cleardanglingscratchdir cli hbaseimport hbaseschematool
 help hiveburninclient hiveserver2 hplsql jar lineage llapdump 
llap llapstatus metastore metatool orcfiledump rcfilecat schemaTool version

1.1 hive cli 服务

默认的服务。输入hive直接启动这个服务,进入cli服务的交互式模式。

[s201 ~]$ hive
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/soft/apache-hive-2.3.4-bin/lib/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/soft/hadoop-2.9.2/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]

Logging initialized using configuration in jar:file:/soft/apache-hive-2.3.4-bin/lib/hive-common-2.3.4.jar!/hive-log4j2.properties Async: true
Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases.
hive> 

进入cli的交互式模式。里面的命令如下

  • quit,exit:  退出交互式shell
  • reset: 重置配置为默认值
  • set <key>=<value> : 修改特定变量的值(如果变量名拼写错误,不会报错)
  • set :  输出用户覆盖的hive配置变量
  • set -v : 输出所有Hadoop和Hive的配置变量
  • add FILE[S] *, add JAR[S] *, add ARCHIVE[S] * : 添加 一个或多个 file, jar, archives到分布式缓存
  • list FILE[S], list JAR[S], list ARCHIVE[S] : 输出已经添加到分布式缓存的资源。
  • list FILE[S] *, list JAR[S] *,list ARCHIVE[S] * : 检查给定的资源是否添加到分布式缓存
  • delete FILE[S] *,delete JAR[S] *,delete ARCHIVE[S] * : 从分布式缓存删除指定的资源
  • ! <command> :  从Hive shell执行一个shell命令
  • dfs <dfs command> :  从Hive shell执行一个dfs命令
  • <query string> : 执行一个Hive 查询,然后输出结果到标准输出
  • source FILE <filepath>:  在CLI里执行一个hive脚本文件
  • !+ shell 命令,可以执行宿主机的命令如   !ls /;
  • dfs 命令可访问Hadoop文件系统

可以在非交互模式下使用cli服务。

script.q是按行分隔的hive命令。这是一个脚本文件。
下面的命令不进入交互式模式而可以直接执行hive脚本。

[s201 ~]$ hive -f script.q


执行单条的hive命令
[s201 ~]$ hive -e 'select * from testTable'

hive会将所有输出打印到标准输出。如果只想看到结果不想看到其他输出信息。
[s201 ~]$ hive -e -S 'select * from testTable'

1.2 hiveserver 服务

hive 以提供Thrift服务的服务器形式运行。允许Hive Thrift client,hive jdbc client, hive odbc连接。设置hive_port来设置该服务器的监听端口号。

启动该服务器的方式:

$>hive --service hiveserver2 &

使用hive jdbc client方式连接到hiveserver。

方式一:使用beeline服务,在命令行连接。

$>beeline						//进入beeline命令行(于hive --service beeline)
$beeline>!help										//查看帮助
$beeline>!quit										//退出
$beeline>!connect jdbc:hive://localhost:10000/mydb2//连接到hibve数据
注,这里连接不上。用
!connect jdbc:hive2://localhost:10000 root
再输入mysql的密码就可以连上了。
具体参考hive的安装配置。
metastore数据存在数据库中,
实际数据存在HDFS上。
所以要连上hive,就需要输入mysql的用户和密码。


$beeline>show databases ;
$beeline>use mydb2 ;
$beeline>show tables;								//显式表

方式二:java编码中使用hive jdbc client方式连接到hiveserver

		

使用Hive-jdbc驱动程序采用jdbc方式访问远程数据仓库
----------------------------------------------------
	1.创建java模块
	2.引入maven
	3.添加hive-jdbc依赖
		<?xml version="1.0" encoding="UTF-8"?>
		<project xmlns="http://maven.apache.org/POM/4.0.0"
				 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
			<modelVersion>4.0.0</modelVersion>

			<groupId>com.it18zhang</groupId>
			<artifactId>HiveDemo</artifactId>
			<version>1.0-SNAPSHOT</version>

			<dependencies>
				<dependency>
					<groupId>org.apache.hive</groupId>
					<artifactId>hive-jdbc</artifactId>
					<version>2.1.0</version>
				</dependency>
			</dependencies>
		</project>

	4.App
		package com.it18zhang.hivedemo;

		import java.sql.Connection;
		import java.sql.DriverManager;
		import java.sql.ResultSet;
		import java.sql.Statement;

		/**
		 * 使用jdbc方式连接到hive数据仓库,数据仓库需要开启hiveserver2服务。
		 */
		public class App {
			public static void main(String[] args) throws  Exception {
				Class.forName("org.apache.hive.jdbc.HiveDriver");
				//Connection conn = DriverManager.getConnection("jdbc:hive2://192.168.231.201:10000/mydb2");
				Connection conn = DriverManager.getConnection("jdbc:hive://192.168.231.201:10000/mydb2");//应该是这个
				Statement st = conn.createStatement();
				ResultSet rs = st.executeQuery("select id , name ,age from t");
				while(rs.next()){
					System.out.println(rs.getInt(1) + "," + rs.getString(2)) ;
				}
				rs.close();
				st.close();
				conn.close();
			}
		}

1.3 hwi 服务

HWI是Hive Web Interface的简称,是hive cli的一个web替换方案。熟悉hive cli就够了,操作hwi更是简单。
所以这里就略过。

1.4 hive jar 服务

hive jar 和Hadoop jar一样,是运行类路径中同时包含Hadoop和hive类java应用程序的方式

1.5 hive metastore服务

要介绍metastore服务,必须先介绍metastore。

metastore包含metastore服务和metastore后台数据的存储。

metastore服务默认是和hive服务程序运行在一个jvm中。我们可以配置metastore服务和hive服务分离,运行在不同的进程中。这样做可以提供更好的管理性和安全性。

如上图,metastare的三种不熟方式。

一:内嵌的metastare。数据库采用内嵌的Derby,一次只能为一个metastare打开一个hive会话。如果尝试打开第二个会话则会报错。

二:本地的metastare。数据库采用mysql,mysql运行在本机或者远程机器。可以打开多个会话。但是metastare服务和hive服务仍然在一个进程中。

三:远程的metastare。数据库采用mysql,mysql运行在本机或者远程机器。可以打开多个会话。metastare服务和hive服务仍然在不同的进程中。

具体的配置,略。入门使用内嵌的,一般情况为了方便都使用本地的,为了考虑安全,商用性可用性等一般使用远程的。

 

 

二:hive和传统关系型数据库的区别

 

Hive

传统数据库

语言

Hql

sql

数据存储

Hdfs

磁盘

执行

MR

Excutor

延迟

低(小规模查询)

处理规模

索引

0.7.0之后开始支持紧凑索引和位图索引

索引,聚集索引非聚集索引

更新,事务,是传统数据库最重要的特征,当然全部支持

更新

不支持Update的delete,支持insert。

后面都支持了

事物

0.13.0之后开始支持事务(表级和分区级),默认不打开,需要配置hive-site参数。

模式

读时模式

写时模式

数据类型除了基础数据类型还支持,数组,映射,结构基础数据类型
多表插入支持不支持
连接内连接,外链接,半连接,映射连接支持,因为hql都是基于此来做的
子查询只能在from字句中,不支持相关的子查询任何子句中支持相关的或者不相关的

关键字解释:

聚集索引:物理上逻辑上都是连续的索引,一个表中只能有一个

非聚集索引:逻辑上连续,物理上不连续的索引,一个表中可以有多个

紧凑索引:存储每个值得hdfs块号。不是存储文件的内偏移量,因此不会占用太多的空间

位图索引:使用压缩的位集合来高效存储具有某个特殊值的行。这种缩影一般适用于较少曲子可能的列,如性别和国籍。

读时模式:对数据的验证不在加载数据的时候验证,而在查询的时候才验证。所以叫读时模式。

写时模式:表的模式在数据加载入数据库的时候就确定了,如果加载时发现数据不符合,就拒绝加载。数据在写入数据库时,对照模式进行检查。所以叫写实模式。

 

三:hive的数据类型详解

3.1基本数据类型

类型名称

大小

示例

TINYINT

1字节整数

45Y

SMALLINT

2字节整数

12S

INT

4字节整数

10

BIGINT

8字节整数

244L

FLOAT

4字节单精度浮点数

1.0

DOUBLE

8字节双精度浮点数

1.0

DECIMAL

任意精度带符号小数

DECIMAL(4, 2)范围:-99.99到99.99

BOOLEAN

true/false

TRUE

STRING

字符串,长度不定

“a”, ‘b’

VARCHAR

字符串,长度不定,有上限

“a”, ‘b’

CHAR

字符串,固定长度

“a”, ‘b’

BINARY

存储变长的二进制数据

 

TIMESTAMP

时间戳,纳秒精度

122327493795

DATE

日期

‘2016-07-03’

说明: 
1,关于整数和小数类型,整数默认情况下为INT,如果要声明为其他类型,通过后缀来标识(Y、S、L)。小数默认为DOUBLE类型,DECIMAL小数点左边允许的最大位数为38位,直接写DECIMAL默认等同于DECIMAL(10,0)。同时任意数值类型都可以隐式转换成更宽的数值类型(不丢精度)或者文本类型。 
2,关于文本类型,STRING存储变长的文本,对长度没有限制。理论上将STRING可以存储的大小为2GB,但是存储特别大的对象时效率可能受到影响。VARCHAR与STRING类似,但是长度上只允许在1-65355之间,超过最大长度会被截断。CHAR则用固定长度来存储数据,最大255。 
3,关于时间和日期类型,Hive提供了一些内置函数用于在TIMESTAMP与Unix时间戳(秒)和字符串之间做转换:

类型转换结果
cast(date as date)相同的日期。
cast(timestamp as date)基于本地时区确定timestamp的年月日作为值返回。
cast(string as date)如果字符串的格式为’YYYY-MM-DD’, 则对应的年月日返回。如果字符串不是该格式,则返回NULL。
cast(date as timestamp)基于本地时区,返回日期对应午夜时间。
cast(date as string)日期被转换为’YYYY-MM-DD’格式的字符串。

3.2复杂数据类型

类型名称大小示例
ARRAY存储同类型数据ARRAY< data_type>
MAPkey-value,key必须为原始类型,value可以是任意类型MAP< primitive_type, data_type>
STRUCT类型可以不同STRUCT< col_name : data_type [COMMENT col_comment], …>
UNION在有限取值范围内的一个值UNIONTYPE< data_type, data_type, …>说明: 


关于元素的访问,ARRAY[1]访问第二个元素; 
map访问元素格式为map[‘key’]; 
STRUCT元素的访问使用点号; 
UNION类型声明语法为UNIONTYPE< data_type,data_type,…>,每个UNION类型的值都通过一个整数来表示其类型,这个整数就是索引,从0开始。例如:

CREATE TABLE union_test(u UNIONTYPE<int, double, array<string>,struct<a:int,b:string>>);  
SELECT u FROM union_test;  
{0:1}  
{1:2.0}  
{2:["three","four"]}  
{3:{"a":5,"b":"five"}}  
{2:["six","seven"]}  
{3:{"a":8,"b":"eight"}}  
{0:9}  
{1:10.0}  

3.3 案例实操

(1)假设有如下json表示的数据结构

{
    "name": "songsong",
    "friends": ["bingbing" , "lili"] ,           //列表Array,
    "children": {                               //键值Map,
        "xiao song": 18 ,
        "xiaoxiao song": 19
    }
    "address": {                               //结构Struct,
        "street": "hui long guan" ,
        "city": "beijing"
    }
}

注意:这里猛的一看,键值对MAP和地址结构Struce。在结构上似乎没太大不同。

在自己设计的时候。怎么样区分这种结构,什么时候用MAP。什么时候用Struct.

 

且找共性:键值Map出。child,每个孩子是不一样的。对应的年龄是不一样的。所以用map结构。

而地址。有两个字段。一个street。一个city。每一个地址都是要有这两个属性的。

如果说child那里也是这样。可以使用性别。年龄。但是有多个孩子。就成了数组。而结构体如果构成数组将变复杂了。

似乎map和结构体可以互相转换。但是寻找一个最优的存储格式。还是有点难。最好就是用单个的数据类型解决。而最好不要用多个数据类型解决。

 

比如。child如果要用结构体来存。也可以。这会构成一个结构体数组,数组成员两个结构体成员。结构体成员有性别和年龄。

这就用到了两个数据结构。而用map一个数据结构就可以解决。

而地址,如果要用map来解决,也可以。会构成一个map数组。数组成员两个map成员。map成员是地区到具体地区,city到具体city的映射、这就太复杂了。所以选择合适的数据结构来存储数据也是一门学问和经验。

 

 

注意,这里存的只是一行的数据,地址这用map其实也是可以的,因为每一行是独立的。只不过结构体更符合逻辑

(2)准备数据文件

 /opt/module/datas/test.txt

songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,hui long guan_beijing
yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,chao yang_beijing

(3)hive上创建表test

create table test(
name string,
friends array<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';                    -- 行分隔符

(4)导入文本数据到测试表

hive (default)> load data local inpath '/opt/module/datas/test.txt’ into table test

(5)访问三种集合列里的数据,以下分别是ARRAY,MAP,STRUCT的访问方式

hive (default)> select friends[1],children['xiao song'],address.city from test where name="songsong";
OK
_c0    _c1    city
lili    18    beijing
Time taken: 1.5 seconds, Fetched: 1 row(s)

hive (default)>hive (default)> select friends,children,address.city from test where name="songsong";
OK
friends                children                                city
["bingbing","lili"]    {"xiao song":18,"xiaoxiao song":19}    beijing
Time taken: 0.07 seconds, Fetched: 1 row(s)

注,hive的文件读取和存储格式不只是text,还有二进制的文件格式,顺序文件,Avro数据文件,以及RCfile文件。

 

四:hive 表数据的导入

4.1 从本地文件系统导入

#创建表结构
hive> CREATE TABLE t_hive (a int, b int, c int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';


hive> LOAD DATA LOCAL INPATH '/home/cos/demo/t_hive.txt' OVERWRITE INTO TABLE t_hive ;
Copying data from file:/home/cos/demo/t_hive.txt


#当然,导入了数据后,就可以通过select * from t_hive来查看数据
hive> select * from t_hive;

4.2 从hdfs文件系统导入

创建表t_hive2
hive> CREATE TABLE t_hive2 (a int, b int, c int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

#从HDFS加载数据
hive> LOAD DATA INPATH '/user/hive/warehouse/t_hive/t_hive.txt' OVERWRITE INTO TABLE t_hive2;


#查看数据
hive> select * from t_hive2;
OK

4.3 从其他hive表导入

hive> INSERT OVERWRITE TABLE t_hive2 SELECT * FROM t_hive ;

overwrite关键字
overwrite关键字的意思是这个表之前的所有数据将会被替换掉。
如果不使用overwrite,
那么该表之前的数据就仍然存在,仅仅是往其中添加新的记录。

上面的语句等同于
FROM t_hive
INSERT OVERWRITE TABLE t_hive2
SELECT *;

4.3.5 多表插入

FORM table2
INSERT OVERWRITE TABLE table_y_c
    SELECT year,CORNT(DISTINCT station)
    GROUP BY year
INSERT OVERWIRTE TABLE records_by_year
    SELECT year COUNT(1)
    GROUP BY year;

多表查询,扫描一个表的数据,插入多个表。
相比多个单独的INSERT语句,效率更高,
因为单独的INSERT语句,会每次都扫描一次表。

 

4.4 创建表的时候从其他表导入

#删除表
hive> DROP TABLE t_hive;

#创建表并从其他表导入数据
hive> CREATE TABLE t_hive AS SELECT * FROM t_hive2 ;

就是被简称称为CTAS SELECT语句。

4.5 复制表

hive> CREATE TABLE t_hive3 LIKE t_hive;


#仅仅拷贝了表的结构
hive> select * from t_hive3;
OK
Time taken: 0.077 seconds

4.6 从mysql数据库导入

这里用到了另一个Hadoop组件sqoop.
在后面的文章中再介绍

五:hive 表数据的导出

5.1将表数据导出到本地文件系统

hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/t_hive' SELECT * FROM t_hive;

...省略中间的打印信息


#查看本地操作系统
hive> ! cat /tmp/t_hive/000000_0;
hive> 1623
611213
41231
17213
71231
11234
11234

5.2 导出到关系型数据库

通过sqoop。

导出到关系型数据库。是因为关系型数据库的查询比较快。

六:hive 表结构的增(创建)删改查

6.1 hive 表结构的增

//准备数据
>vi /home/cos/demo/t_hive.txt
16      2       3
61      12      13
41      2       31
17      21      3
71      2       31
1       12      34
11      2       34

//进入hive
>hive shell
hive>

//创建新表
hive> CREATE TABLE t_hive (a int, b int, c int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

//导入数据
hive> LOAD DATA LOCAL INPATH '/home/cos/demo/t_hive.txt' OVERWRITE INTO TABLE t_hive ;


6.2 hive 表结构的查

#查看表 
hive> show tables;
t_hive


#正则匹配表名
hive>show tables '*t*';
t_hive

#查看表数据
hive> select * from t_hive;


#查看表结构
hive> desc t_hive;
OK
a       int
b       int
c       int

6.3 hive 表结构的改

#增加一个字段
hive> ALTER TABLE t_hive ADD COLUMNS (new_col String);

hive> desc t_hive;
OK
a       int
b       int
c       int
new_col string


#重命令表名
~ ALTER TABLE t_hive RENAME TO t_hadoop;

hive> show tables;
OK
t_hadoop

6.4 hive 表结构的删

hive> DROP TABLE t_hadoop;

//查看有哪些表的时候已经没有这个表的存在了
hive> show tables;

七:排序

order by

order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)
只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
set hive.mapred.mode=nonstrict; (default value / 默认值)
set hive.mapred.mode=strict;
 order by 和数据库中的Order by 功能一致,按照某一项 & 几项 排序输出。 与数据库中 order by 的区别在于在hive.mapred.mode = strict 模式下 必须指定 limit 否则执行会报错。
hive> select * from test order by id;     
FAILED: Error in semantic analysis: 1:28 In strict mode, if ORDER BY is specified, LIMIT must also be specified. Error encountered near token 'id'
原因: 在order by 状态下所有数据会到一台服务器进行reduce操作也即只有一个reduce,如果在数据量大的情况下会出现无法输出结果的情况,如果进行 limit n ,那只有  n * map number 条记录而已。只有一个reduce也可以处理过来。

sort by

sort by不是全局排序,其在数据进入reducer前完成排序.
因此,如果用sort by进行排序,并且设置mapred.reduce.tasks>1, 则sort by只保证每个reducer的输出有序,不保证全局有序。
sort by 不受 hive.mapred.mode 是否为strict ,nostrict 的影响sort by 的数据只能保证在同一reduce中的数据可以按指定字段排序。使用sort by 你可以指定执行的reduce 个数 (set mapred.reduce.tasks=<number>),对输出的数据再执行归并排序,即可以得到全部结果。

注意:可以用limit子句大大减少数据量。使用limit n后,传输到reduce端(单机)的数据记录数就减少到n* (map个数)。否则由于数据过大可能出不了结果。

 

distribute by

 按照指定的字段对数据进行划分到不同的输出reduce  / 文件中。
 insert overwrite local directory '/home/hadoop/out' select * from test order by name distribute by length(name);  
 此方法会根据name的长度划分到不同的reduce中,最终输出到不同的文件中。 
 length 是内建函数,也可以指定其他的函数或这使用自定义函数。

Cluster By

 cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能。 
但是排序只能是倒序排序,不能指定排序规则为asc 或者desc。

八:hive的连接查询,聚合查询,子查询,视图

8.1 连接查询

//内连接查询,据说hive不支持这种语法的内连接
hive> select a.*,b.* from customers a , orders b where a.id = b.cid ;
//内连接查询
hive>select a.*,b.* from customers a      outer join orders b on a.id = b.cid ;
//左外连接
hive>select a.*,b.* from customers a left outer join orders b on a.id = b.cid ;
//右外连接
hive>select a.*,b.* from customers a right outer join orders b on a.id = b.cid ;
//全外连接
hive>select a.*,b.* from customers a full outer join orders b on a.id = b.cid ;

//半连接 据说hive不支持这种语法
select * from things_table 
where things_table.id IN (select id from sales);
//半连接,所以引入这个语法代替
SELECT * 
FROM things_table LEFT SEMI JOIN sales ON (sales.id = things_table.id);


map连接
如果要使用map连接,需要再其中加入C语言风格的注释,表示这个是一个MAP连接。
SELECT /* + MAPJOIN(things) */ sales.* things.*
FROM sales JOIN things ON (sales.id = things.id);

8.2 聚合查询

# count, avg
hive> SELECT count(*), avg(a) FROM t_hive;
7       31.142857142857142


# count,distinct
hive> SELECT count(DISTINCT b) FROM t_hive;
3


# GROUP BY
hive> SELECT avg(a),b,sum(c) FROM t_hive GROUP BY b,c
16.0    2       3
56.0    2       62
11.0    2       34
61.0    12      13
1.0     12      34
17.0    21      3

# HAVING
hive> SELECT avg(a),b,sum(c) FROM t_hive GROUP BY b,c HAVING sum(c)>30
56.0    2       62
11.0    2       34
1.0     12      34

8.3 子查询

子查询指的是内嵌在另一个SQL语句中的SELECT语句。

hive只允许子查询出现在SELECT语句中的FROM子句。

SELECT station,year
FROM (
    SELECT station,year
    FROM record2
    ) mt
GROUP BY station;

 8.4视图

//创建视图
$hive>create view v1 as select a.id aid,a.name ,b.id bid , b.order \
from customers a left outer join default.tt b on a.id = b.cid ;

//查看视图
$hive>show tables ;
$hive>select * from v1 ;

 

九:hive的分区和桶

9.1 静态分区

Hive分区的概念与传统关系型数据库分区不同。
传统数据库的分区方式:就oracle而言,分区独立存在于段里,里面存储真实的数据,在数据进行插入的时候自动分配分区。Hive的分区方式:由于Hive实际是存储在HDFS上的抽象,Hive的一个分区名对应一个目录名,子分区名就是子目录名,并不是一个实际字段。

(1)单个分区

创建分区

create table par_tab (name string,nation string) \
partitioned by (sex string) \
row format delimited fields terminated by ',';

该分区表的表结构:

hive> desc par_tab;
OK
name                    string                                      
nation                  string                                      
sex                     string                                      
          
# Partition Information          
# col_name                data_type               comment             
          
sex                     string                                      
Time taken: 0.038 seconds, Fetched: 8 row(s)

 准备数据

jan,china
mary,america
lilei,china
heyong,china
yiku,japan
emoji,japan

数据插入分区表

load data local inpath '/home/hadoop/files/par_tab.txt' into table par_tab partition (sex='man');

查看表数据

hive> select * from par_tab;
OK
jan    china    man
mary    america    man
lilei    china    man
heyong    china    man
yiku    japan    man
emoji    japan    man
Time taken: 0.076 seconds, Fetched: 6 row(s)

 查看表存储在hdfs上的目录结构

[hadoop@hadoop001 files]$ hadoop dfs -lsr /user/hive/warehouse/par_tab

drwxr-xr-x   - hadoop supergroup          0 2017-03-29 08:25 /user/hive/warehouse/par_tab/sex=man
-rwxr-xr-x   1 hadoop supergroup         71 2017-03-29 08:25 /user/hive/warehouse/par_tab/sex=man/par_tab.txt

再准备数据

lily,china
nancy,china
hanmeimei,america

再插入数据

load data local inpath '/home/hadoop/files/par_tab_wm.txt' into table par_tab partition (sex='woman');

再查看表数据

hive> select * from par_tab;
OK
jan    china    man
mary    america    man
lilei    china    man
heyong    china    man
yiku    japan    man
emoji    japan    man
lily    china    woman
nancy    china    woman
hanmeimei    america    woman
Time taken: 0.136 seconds, Fetched: 9 row(s)

再查看表在hdfs上的存储结构

[hadoop@hadoop001 files]$ hadoop dfs -lsr /user/hive/warehouse/par_tab
drwxr-xr-x   - hadoop supergroup          0 2017-03-29 08:25 /user/hive/warehouse/par_tab/sex=man
-rwxr-xr-x   1 hadoop supergroup         71 2017-03-29 08:25 /user/hive/warehouse/par_tab/sex=man/par_tab.txt
drwxr-xr-x   - hadoop supergroup          0 2017-03-29 08:35 /user/hive/warehouse/par_tab/sex=woman
-rwxr-xr-x   1 hadoop supergroup         41 2017-03-29 08:35 /user/hive/warehouse/par_tab/sex=woman/par_tab_wm.txt

查询指定分区的表数据

hive> select * from par_tab where sex='woman';
OK
lily    china    woman
nancy    china    woman
hanmeimei    america    woman
Time taken: 0.515 seconds, Fetched: 3 row(s)

(2)多分区

创建多分区的表

hive> create table par_tab_muilt (name string, nation string) \
partitioned by (sex string,dt string) \
row format delimited fields terminated by ',' ;


hive> load data local inpath '/home/hadoop/files/par_tab.txt' \
into table par_tab_muilt partition (sex='man',dt='2017-03-29');

查看存储在hdfs上的目录结构。与单个分区表的不同的

[hadoop@hadoop001 files]$ hadoop dfs -lsr /user/hive/warehouse/par_tab_muilt
drwxr-xr-x   - hadoop supergroup          0 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man
drwxr-xr-x   - hadoop supergroup          0 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2017-03-29
-rwxr-xr-x   1 hadoop supergroup         71 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2017-03-29/par_tab.txt

9.2 动态分区

 启用动态分区

hive> set hive.exec.dynamic.partition=true;

插入数据(dt是冬天分区)

hive> insert overwrite table par_dnm partition(sex='man',dt)
    > select name, nation, dt from par_tab;

 注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区。

 动态分区可以允许所有的分区列都是动态分区列,但是要首先设置一个参数

hive> set hive.exec.dynamic.partition.mode=nostrick;

 9.3 桶

 

十:hive 自定义函数

1.创建类,继承UDF
		package com.it18zhang.hivedemo.udf;

		import org.apache.hadoop.hive.ql.exec.Description;
		import org.apache.hadoop.hive.ql.exec.UDF;

		/**
		 * 自定义hive函数
		 */
		@Description(name = "myadd",
				value = "myadd(int a , int b) ==> return a + b ",
				extended = "Example:\n"
						+ " myadd(1,1) ==> 2 \n"
						+ " myadd(1,2,3) ==> 6;")
		public class AddUDF extends UDF {

			public int evaluate(int a ,int b) {
				return a + b ;
			}

			public int evaluate(int a ,int b , int c) {
				return a + b + c;
			}
		}
	2.打成jar包。
		cmd>cd {classes所在目录}
		cmd>jar cvf HiveDemo.jar -C x/x/x/x/classes/ .
	3.添加jar包到hive的类路径
		//添加jar到类路径
		$>cp /mnt/hgfs/downloads/bigdata/data/HiveDemo.jar /soft/hive/lib
	
	3.重进入hive
		$>....

	4.创建临时函数
		//
		CREATE TEMPORARY FUNCTION myadd AS 'com.it18zhang.hivedemo.udf.AddUDF';

	5.在查询中使用自定义函数
		$hive>select myadd(1,2)  ;
	
	6.定义日期函数
		1)定义类
		public class ToCharUDF extends UDF {
			/**
			 * 取出服务器的当前系统时间 2017/3/21 16:53:55
			 */
			public String evaluate() {
				Date date = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat();
				sdf.applyPattern("yyyy/MM/dd hh:mm:ss");
				return sdf.format(date) ;
			}
			public String evaluate(Date date) {
				SimpleDateFormat sdf = new SimpleDateFormat();
				sdf.applyPattern("yyyy/MM/dd hh:mm:ss");
				return sdf.format(date) ;
			}

			public String evaluate(Date date,String frt) {
				SimpleDateFormat sdf = new SimpleDateFormat();
				sdf.applyPattern(frt);
				return sdf.format(date) ;
			}
		}

		2)导出jar包,通过命令添加到hive的类路径(不需要重进hive)。
			$hive>add jar /mnt/hgfs/downloads/bigdata/data/HiveDemo-1.0-SNAPSHOT.jar
		
		3)注册函数
			$hive>CREATE TEMPORARY FUNCTION to_char AS 'com.it18zhang.hivedemo.udf.ToCharUDF';
			$hive>CREATE TEMPORARY FUNCTION to_date AS 'com.it18zhang.hivedemo.udf.ToDateUDF';

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值