3.Hadoop Hive服务

接上文—————>

目录:

  • 一.安装
  • 二.have基本命令操作
  • 三.hive数据仓库
  • 四.hive表的类型:
  • 五.hive中重要的元数据表
  • 六.hive的连接方式
  • 七.使用jdbc编写外部程序操作hive
  • 八.hive的基本数据类型
  • 九.hive的复杂的数据类型
  • 十.hive的建表语句
  • 十一.hive 删除表
  • 十二.hive 修改表
  • 十三.查看表信息
  • 十四.DML
  • 十五.hive单词统计 (count)
  • 十六.hive分布表
  • 十七.分桶表
  • 十八.hive排序
  • 十九.hive变量:
  • 二十.hive命令行中执行hadoop命令
  • 二十一.hive表的数据类型与文件格式:
  • 二十二.数据操作
  • 二十三.在hive中何时不会hql转换为mr执行
  • 二十四.hive常用函数:
  • 二十五.hive中事务的使用
  • 二十六.操作:
  • 二十七.操作:
  • 二十八.hive的优化
  • 二十九.UDF:User define function 用户自定义函数

一.安装

1.解压下面压缩包

tar -xzvf apache-hive-2.1.1-bin.tar.gz

2.重命名

mv apache-hive-2.1.1-bin hive

3.配置环境变量
进入文件:

 vi /etc/profile

填入环境变量(注意修改hive路径):

#HIVE                      
export HIVE_HOME=/root/soft/hive
export PATH=$PATH:$HIVE_HOME/bin  

更新文档:

source /etc/profile

检验hive版本(出现版本号说明成功):

hive --version

4.修改hive-site.xml

cd /soft/hive/conf

重命名:

cp hive-default.xml.template hive-site.xml

进入文件修改:

vi hive-site.xml

修改以下环境变量(推荐Notepad++软件编辑):

javax.jdo.option.ConnectionUserName  = 改为mysql 用户名
javax.jdo.option.ConnectionPassword  = 改为mysql 密码
javax.jdo.option.ConnectionURL = jdbc:mysql://你的IP:3306/hive
javax.jdo.option.ConnectionDriverName = com.mysql.jdbc.Driver  (直接复制这是MySQL驱动)  

5.将mysql-connector-java-5.1.18-bin.jar连接驱动包上传到hive/lib下
3.Hadoop Hive服务_第1张图片 6.需要在MySQL下建立hive数据库: 3.Hadoop Hive服务_第2张图片

7.在Hadoop下创建hive临时目录:

 hdfs dfs -mkdir -p /soft/hive/tmp

8.修改hive-site.xml文件,设定为false

将${system:java.io.tmpdir} 替换为 /soft/hive/tmp 
将${system:user.name} 替换为 root

9.Linux输入schematool -dbType mysql -initSchema进行初始化:

schematool -dbType mysql -initSchema

出现如下completed则成功:
3.Hadoop Hive服务_第3张图片
10.执行hive命令测试是否能进入 hive>

hive

在这里插入图片描述

hive环境搭建到此结束.

二.have基本命令操作


1. 查看数据库
	$hive> show databases;
2. 创建数据库
	$hive> create database db1;
3. 选择某个数据库
	$hive> use db1;
4. 删除数据库
	$hive> drop db1;
	
[结论] 
	1. 通过查看hdfs中的目录结构,确定了hive中的数据库就是hdfs中的一个文件夹(dbname.db)
		$> hdfs dfs -lsr /
	2. 在元数据库中(mysql), 存储了数据库的数据结构(dbs)。
		$mysql> use hive ;
		$mysql> select * from dbs;


5. 清空hive命令行
	$hive> !clear;
   查看表
	$hive> show tables;

6. 查询表
   $hive> select * from employee;
7. 创建表(*****)
	内部表
	外部表
	分区表
	桶表
	
	($hive> create table db1.employee(id int,name string,age int);(没有数据加入))
	$hive> create table db1.employee(id int,name string,age int) row format delimited fields terminated by '\t' stored as textfile ;
	(创建的是内部表)
	注意: 一定要使用数据库名.表名创建
	$mysql> select * from tbls;查看属于那个数据库
	
8. 修改表(不建议)
	$hive> alter table db1.employee add column (sid string);

9. 删除表
	$hive> drop table db1.employee;
	
10. 添加数据(新增数据)做此操作,必须启动yarn!
	$hive> insert into db1.employee(id,name,age) values(1,'xxx',18); (不推荐, 会将语句转换为mr执行,效率低)
    $mysql> select * from columns_v2;CD_ID查看表信息
	$mysql> select * from tbls;SD_ID列
11. 加载数据(常用的三种方式)
	[准备工作]
	    cd ~
		mkdir data
		touch d.txt
		vi d.txt
		mv d.txt data
		创建一个文件d.txt(用tab建隔开)
		-------------------------
		1	xiaoming	17
		2	xiaohong	18
		3	xiaoqiang	19

	create table test_part (id int,name string,no int) 
	row format delimited fields terminated by '\t'  
	stored as textfile ;
	
	1. 拷贝
		$> hdfs dfs -put ~/data/d.txt /root/hive/warehouse/db1.db/employee
		$hive> select * from employee;
	2. 加载linux本地文件 什么类型的数据都可以拷贝分片
		$hive> load data local inpath '/home/centos/data/d.txt' into table employee;
		$hive> select * from employee;
	3. 加载hdfs文件
	    $> hdfs dfs -mkdir -p /root/hive/data
		$> hdfs dfs -put ~/data/d.txt /root/hive/data
		$> hdfs dfs -lsr /root/hive/data
		$hive> load data inpath '/root/hive/data/d.txt' into table employee;
		$hive> select * from employee;
		
12. insert与load区别:
    load data:将某些数据文件上传至hdfs,数据量大
          insert:将insert操作转换为mr作业,每一次进行insert的话,在表目录下生成一个新的数据文件
   
    cd data
    vi a.txt
    输入:(tab键隔开)
    4	xiaogang	20
    5	xiaowang	21

    $> hdfs dfs -put a.txt /root/hive/warehouse/db1.db/employee
    $> hdfs dfs -lsr /
    $hive> use db1;
    $hive> select * from employee;
    $hive> inser into employee(id,name,age) values(6,'yyy',19);
    访问http://192.168.110.3:8088 查看yarn进程
    $> hdfs dfs -lsr / 
       多出来一个/root/hive/warehouse/db1.db/employee/000000_0
    $> hdfs dfs -cat /root/hive/warehouse/db1.db/employee/000000_0
       显示  6	yyy	19
   
13. hive不支持update,delete操作

14. 排序操作
    order by 字段 asc\desc
	order by 操作转换成mapreduce
	
    $hive> select * from employee order by id desc;//降序
	
15. 分页操作
    oracle: rownum(数据伪列)
	        select * from xxx where rownum >=10 and rownum <20;
	mysql: limit 数据开始条数,数据条数;
	       select * from xxx limit 10,10;
	limit操作不会转换成mapreduce
	
	$hive> select * from employee order by id asc limit 0,5;//查询排序后的前5条记录(1,2,3,4,5)
	$hive> select * from employee limit 0,5;//查询当前的前5条记录

16. 子查询
    建表:
	    1. user
		   $hive> create table db1.usr(uid int,uname string,rid int) row format delimited fields terminated by ',' stored as textfile;
		   --------------------
		   cd data
		   vi usr.txt
		   输入:
		   1,admin,1
		   2,user1,2
		   3,user2,2
		   4,user3,3
		   
		   $hive> load data local inpath '/home/centos/data/usr.txt' into table db1.usr;
		2. role
		   $hive> create table db1.role(rid int,rname string) row format delimited fields terminated by ',' stored as textfile;
		   -------------------
		   cd data
		   vi role.txt
		   输入:
		   1,管理员
		   2,工程师
		   
		   $hive> load data local inpath '/home/centos/data/role.txt' into table db1.role;
		   
		* 查询user表中rid在role中存在的数据。转换成mapreduce
		$hive> select * from usr where rid in (select rid from role); 
		     结果: 1	admin	1
			        2	user1	2
					3	user2	2
		   
17. 连接查询
    ------------------
	[需求]查询用户的账号以及角色名。
	
    inner :多表匹配,匹配不到的数据不显示
	    [语句]
		-------
		    sql 1993:(不好使用外连接)
			    $hive> select u.uname,r.rname from usr u,role r where u.rid =r.rid;
				结果:
				    admin 管理员
					user1 工程师
					user2 工程师
			sql 1998:
			    $hive> select u.uname,r.rname from usr u inner join role r on u.rid=r.rid;
				
	outer :按特定的表匹配,匹配不到的数据使用null填充
	    - left 以左边的表为基准
		    $hive> select u.uname,r.rname from usr u left outer join role r on u.rid=r.rid;
			结果:
			    admin 管理员
				user1 工程师
				user2 工程师
				user3 NULL
		- right
		    $hive> select u.uname,r.rname from usr u right outer join role r on u.rid=r.rid;
		- full
		    $hive> select u.uname,r.rname from usr u full outer join role r on u.rid=r.rid;
		
	连接查询会将操作转换成mapreduce执行。

三.hive数据仓库


数据仓库:OLAP(在线分析处理):延迟高,处理数据量大,不支持在线事务
数据库:OLTP(在线事务处理):延迟低,处理数据量没有那么大,支持事务

四.hive表的类型:


内部表(托管表)
    create table : 当删除表(drop table)时,元数据(MySQL)和数据文件(hdfs)都会被删除。
外部表
    create external table : 元数据和数据文件分离,当删除表时,元数据会删除,数据文件会保留。
	                        (表没有了,但数据还保留着)
分区表
    由于在hive下每一个表就是一个文件夹,数据就是文件。在一个文件夹下有可能存储特别多的数据文件。
	这时,当执行数据分析操作时,会遍历整个表文件夹下的所有文件,执行效率是比较低下的。
	分区表就是在表文件夹下继续分子文件夹,加载数据(load)时,数据会根据命令进入到不同的分区文
	价夹,这样我们在进行数据分析时,就可以根据分区逻辑进行查询了。
桶表
    有可能在分区子文件中数据文件依然很大,hive可以自定义分桶规则,对这些文件进行分桶(根据数据
	hash值,把数据分入到不同的桶文件),继续提高查询效率。

五.hive中重要的元数据表


            DBS         -> hive数据库的信息
TBLS        -> hive表的信息
SDS         -> hive文件信息
COLUMNS_V2  -> hive表的列信息
PARTITIONS  -> hive表的分区信息

六.hive的连接方式


hive 命令 cli 和 beeline 2选一
1. hive cli
------------
    在hive2.0之前,最常用的一种命令,只能在本机运行。
	$> hive --service cli  等同于 $>hive
	
	常用参数
	-d 以键值对的形式定义一个变量,可以在命令行中使用
	    [centos@master bin]$>hive -d tab=employee    ->在Linux中 直接声明变量tab
		$hive> use db1;
		$hive> select * from ${tab} ;  ->在hive命令行中直接引用
		
	-e 在Linux中直接使用hive命令执行某条Hql语句
	    [centos@master bin]$>hive -e "select * from db1.employee"
		执行完后直接退出hive,回到Linux命令行窗口
		
	-f 在Linux中直接执行某个hql文件
	    $>cd ~
		$>mkdir hql
		$>touch hive1.hql
		$>vi hive1.hql
	    $>cat hive1.hql
		  --------------
		  use db1;
		  select * from db1.employee;
		[centos@master hql]$ hive -f hive1.hql
		$>hive -f ~/hql/hive1.hql
		执行完后直接退出hive,回到Linux命令行窗口
		
2. hive beeline
    在hive2.0之后的,准备替换cli一个命令行,支持本机运行和远程运行
	------------------------------------
	修改Hadoop的core-site.xml
	------------------------------
	
	  hadoop.proxyuser.centos.hosts
	  *
	
	
	  hadoop.proxyuser.centos.groups
	  *
	
	修改hdfs-site.xml
	
	  dfs.webhdfs.enabled
	  true
	
	打开服务,打开另一个窗口专门运行hive服务,因为它不在后台运行。
	$>hive --service hiveserver2  //开启了一个RunJar节点
	
	$>beeline -u jdbc:hive2://master:10000
	    -n 用户名
		-p 密码
	
3. hive server2
-------------------
    hive server2 本身是一个服务 RunJar
    hive 对外提供的连接端口
	10000:外部连接端口
	10002:webUI端口
        http://192.168.110.3:10002/hiveserver2.jsp  连接hive server2 的webUI

七.使用jdbc编写外部程序操作hive


1.导入hive相关依赖

  
    org.apache.hive
    hive-jdbc
    2.1.1
  

2.编写hive的jdbc程序
public static void main(String[] args) throws Exception{
    Class.forName("org.apache.hive.jdbc.HiverDriver");
	Connection conn=DriverManger.getConnection("jdbc:hive2://192.168.58.100:10000/db1","centos","123456");
	Statement stmt=conn.createStatement();
	ResultSet rs = stmt.executeQuery("select * from employee");
	while(rs.next()){
	    System.out.println(rs.getInt("id"),rs.getString("name"),rs.getInt("age"));
	}

    rs.close();
    stmt.close();
    conn.close();
    }

八.hive的基本数据类型


在hive中声明列的时候不需要指明列的长度。
    MySQL:
	    create table user(id int(32),name varchar(32));
	hive:
	    create table user(id int,name string);
		
整数:
    tinyint -> byte(Java) -> 1字节
	smallint -> short(Java) -> 2字节
	int -> 4字节
	bigint -> long(Java) -> 8字节
小数:
    float:单精度浮点
    double:	双精度浮点
字符串:
    string -> varchar(mysql)
布尔:
    boolean -> true / false

九.hive的复杂的数据类型


1. Map : 一组有序的字段,字段类型必须相同(Java中的List)
2. Array : 无序键值对,键值对内部字段类型(Java中的value)必须相同(Java中的Map)
3. Struct : 一组字段,字段类型可以不同(Object集合)

十.hive的建表语句


create [external](外部表) table [if not exists(判断是否存在)] table_name
(col1_name(列名) type(类型) [comment col_comment(对列的说明)],col2_name type [comment col_comment]....)
[comment table_comment]
partitioned by(分区表)(col1_name type [comment col_comment],col2_name type [comment col_comment]...)
row format delimited fields terminated by ','
clustered by(分桶表)(col_name)(需要分桶的字段) into  n(桶的数目)buckets
stored by file_type(数据文件存储类型)
location hdfs_path(文件存储位置);

1. external:在建表语句中添加external选项,代表这个表为外部表。
    外部表在删表时,只删元数据(mysql),不删数据文件(hdfs),故删除后数据一般不会丢
[创建student(sid sname age)]
	1创建内部表:
      $hive> create table student_1(sid int , sname string,age int) row format delimited fields terminated by ',';
		 [centos@master ~]$cd data/
		 [centos@master data]$ touch student.txt
		 [centos@master data]$ vi student.txt
	  $hive>load data local inpath '/home/centos/data/student.txt' into table student_1;
	2创建外部表:
	  $hive> create external table if not exists student_2(sid int , sname string,age int) row format delimited fields terminated by ',';
	mysql元数据中的区别(tbls表中 TBL_TYPE字段有区别):
	    内部表:MANAGED_TABLE
	    外部表:EXTERNAL_TABLE
	数据文件区别:	
	    $> hdfs dfs -lsr /
	      drwxrwxrwx   - centos supergroup          0 2020-04-01 20:07 /root/hive/warehouse/db1.db/student_1
          -rwxrwxrwx   1 centos supergroup         28 2020-04-01 20:07 /root/hive/warehouse/db1.db/student_1/student.txt
          drwxrwxrwx   - centos supergroup          0 2020-04-01 20:17 /root/hive/warehouse/db1.db/student_2
          -rwxrwxrwx   1 centos supergroup         28 2020-04-01 20:17 /root/hive/warehouse/db1.db/student_2/student.txt
	执行删表操作时,mysql元数据删除,内部表会删除hdfs上的数据文件,外部表不删除
	    $hive> drop table student_1;
		$hive> drop table student_2;
		
	    $> hdfs dfs -lsr /
	      drwxrwxrwx   - centos supergroup          0 2020-04-01 20:17 /root/hive/warehouse/db1.db/student_2
          -rwxrwxrwx   1 centos supergroup         28 2020-04-01 20:17 /root/hive/warehouse/db1.db/student_2/student.txt
2. comment :注释
    table comment : 表声明语句后(表名后面)
	column comment : 字段声明语句后(列后面)
3. 指定字段分割符
    row format delimited fields terminated by ',' : 在某张表中的字段是以","作为分隔符的,在load数据时数据文件以,分割
4. partitioned by 分区表
    分区表就是表文件夹下多个子文件夹。
	-------------------------------
	    分区表:
		    1. 创建分区表:
			    $hive> create external table stu (sid int,sname string) partitioned by(bir_year int,bir_month int) row format delimited fields terminated by ',';
					[centos@master data]$ touch stu.txt
					[centos@master data]$ vi stu.txt
					[centos@master data]$ cp stu.txt stu1.txt

			2. 上传文件
			    $hive> load data local inpath '/home/centos/data/stu.txt' into table stu partition (bir_year = 2000,bir_month = 10);
				$hive> load data local inpath '/home/centos/data/stu1.txt' into table stu partition (bir_year = 2000,bir_month = 11);
				影响数据存储,但不影响数据分析
				$> hdfs dfs -lsr /
				    drwxrwxrwx   - centos supergroup          0 2020-04-02 16:54 /root/hive/warehouse/db1.db/stu
                    drwxrwxrwx   - centos supergroup          0 2020-04-02 16:55 /root/hive/warehouse/db1.db/stu/bir_year=2000
                    drwxrwxrwx   - centos supergroup          0 2020-04-02 16:54 /root/hive/warehouse/db1.db/stu/bir_year=2000/bir_month=10
                    -rwxrwxrwx   1 centos supergroup         23 2020-04-02 16:54 /root/hive/warehouse/db1.db/stu/bir_year=2000/bir_month=10/stu.txt
                    drwxrwxrwx   - centos supergroup          0 2020-04-02 16:55 /root/hive/warehouse/db1.db/stu/bir_year=2000/bir_month=11
                    -rwxrwxrwx   1 centos supergroup         23 2020-04-02 16:55 /root/hive/warehouse/db1.db/stu/bir_year=2000/bir_month=11/stu1.txt
				$hive> select * from stu;
					1	tom	2000	10
					2	jerry	2000	10
					3	jorden	2000	10
					1	tom	2000	11
					2	jerry	2000	11
					3	jorden	2000	11

5. clustered by (col_name) into n buckets
    桶表:根据某个字段,将数据分入不同的文件中
6. stored by file_type
    指定hdfs中数据文件的类型:
	    textfile     : 文本文件
		sequencefile : 序列文件
		rcfile       :
		orcfile      : 二进制文件(常用)

十一.hive 删除表


$hive> drop table table_name;

十二.hive 修改表


修改表名
    alter table employee(旧) rename to emp(新);
添加列
    alter table emp add columns (cls(列名) string);
修改列类型
	alter table emp replace columns (cls int(类型));

十三.查看表信息


desc formatted table_name;

十四.DML


加载文件
    load data [local] inpath 'file path' [overwrite] into table tablename [partition (partcol1 = value1,partcol2 = value2)];
        'file path' ——> '文件路径' 
		有local是Linux上的文件,不加是hdfs
		[overwrite] ——> 重写
		[partition (partcol1 = val1,partcol2 = val2)] ——> 分区(分区列=......)
	1. 加载文件 只是单纯的复制/移动操作,将数据文件移动到hive表所在的位置(在Hdfs上)
	2. 'file path'
	    相对路径
			load data local inpath 'data/stu1.txt' into table stu partition (bir_year = 2000,bir_month = 11);
		绝对路径
			load data local inpath '/home/centos/data/stu1.txt' into table stu partition (bir_year = 2000,bir_month = 11);
		完整URI
		    load data local inpath 'hdfs://master:9000/user/live/data/data.txt' into table stu partition (bir_year = 2000,bir_month = 11);
    3. local : linux(加) / hdfs(不加)
	4. overwrite : 
	    使用overwrite,目标表(或者分区)中的内容如果存在就会被删除,然后再将file path指向的文件/目录中的内容添加到表/分区的目录中。
		如果目标表(分区)已经有文件,并与filepath中的文件名冲突,新的文件会替换旧数据文件。
插入操作	

十五.hive单词统计 (count)


(words.txt中每一行的数据存储到textlines表中每一行,line代表数据文件中的每一行数据,再利用explode()展开函数将textlines表中的每一行展开,展开后的数据存储在words表中)

准备数据
    words.txt               -> textlines                -> words
	----------               ---------------            --------------
	hadoop,java,hive            line (列,有三条数据)     word(字段,展开的记录)
	hive,c,hadoop               hadoop,java,hive            hadoop
	hive,java,c                 hive,c,hadoop               java
	                            hive,java,c                 hive
								                          
方法一:1. 分布查询(mr思路)
-------------
    1.1 建表(line代表数据文件中的每一行数据)
	    textlines(line string);
		hive>create table textlines(line string);
	1.2 建表(word代表每一个单词)
	    words(word string);
		hive>create table words(word string);
	1.3 加载数据(words.txt -> textlines,即从文件中插入到表中)
	    load data 'xxx' into table textlines;
		hive>load data local inpath '/home/centos/data/words.txt' into table textlines;
   *1.4 拆分单词并插入words表(textlines -> words,即将表中每一行数据进行拆分,将数据插入到另一表中,语句中的line是表中的列名)
	    hive>insert overwrite table words select explode(split(line,',')) as word from textlines;
		步骤解析:1查询语句:先将行按照,作为标志进行分割,但此时仍为行并不为列
		            select (split(line,','))
				  2查询语句:将分割好的每一行进行转列,并为数据表起别名为word
				    select explode(split(line,',')) as word from textlines
				  3插入语句:将查询出的数据插入到另一张表中
				    insert overwrite table words select explode(split(line,',')) as word from textlines;
	1.5 进行单词统计
	    select word, count(*) from words group by word;
		hive>select word, count(word) as cont from words group by word;

方法二:2. hql子查询(此法可省略words表)
----------------
    准备工作:即1.1和1.3
	    将数据插入到textlines;
	实质是1.4和1.5的结合给(select explode(split(line,',')) as word from textlines)表添加别名为w	
		hive>select w.word, count(*) from (select explode(split(line,',')) as word from textlines) as w group by w.word;
		
3. 函数介绍
-----------------
    explode() :展开函数 -> 行转列
	split()   :分割函数

十六.hive分布表


create [external] table [if not exists] table_name
(col1_name type [comment col_comment],col2_name type [comment col_comment]....)
[comment table_comment]
partitioned by (col1_name type [comment col_comment],col2_name type [comment col_comment]...) ->存在此行是分区表
clustered by (col_name) into n buckets
stored by file_type
location hdfs_path
row format delimited fields terminated by ',';

分区:
---------------------------
    严格模式    :  hive.exec.dynamic.partition.mode = strict;
	    由于hive是分布式的数据仓库,而这个数据仓库中每一张表中都存在大量的数据,这些数据是以文件的形式存储的。
		所以我们在执行某些HQL的时候,效率的非常低。严格模式下,只允许静态分区。
	非严格模式  :  hive.exec.dynamic.partition.mode = nonstrict;
	    为了提高某些hql语句的执行效率,启动非严格模式,用户就可以在加载数据时形成新的分区。
    静态分区:在严格模式下,用户只能通过建表来确定分区,加载数据时确定分区,加载数据时不能创建新的分区
	动态分区:非严格模式下,用户可以通过load data 或 insert ... select 创建的新的分区(若出错检查是否配置)
	    
		动态分区出现的目的(严格模式的一些限制):
		-------------------------------
		    防止用户查询时出现意外
			1. 带有分区表的查询:在严格模式下,用户不允许扫描所有的分区
			        进行这个限制的原因:通常分区表都有非常大量的数据集,而且数据增长非常迅速。
			2. 进行order by查询:在严格模式下,用户在进行order by 操作时,必须添加limit操作。(?)
			3. 进行join操作(笛卡尔积):
			    MySQL :select a.a,a.b,b.a,b.b from a join b where a.xx = b.xx;
				MySQL中可以将join where 语句转换为 join on 语句的。
				Hive :在严格模式下 join where 是不允许的。
			4. 严格模式下限制bigint类型数据与string和double进行比较。
	
	
hive中修改配置的两种常用方法:
    1. 临时 :只在当前会话中起作用
	    $hive> set hive.exec.dynamic.partition=true     ->允许hive使用动态分区
	    $hive> set hive.exec.dynamic.partition.mode = nonstrict;    ->打开非严格模式,表示所有分区为动态
		
		性能设置:
		     最大动态分区数:
			     hive.exec.max.dynamic.partition.pernode = 100(默认值,可修改,在hive.site中修改)
			 一个动态分区创建语句可以创建的最大动态分区数:
			     hive.exec.max.dynamic.partitions = 1000 (默认值,可修改,在hive.site中修改)
	         全局最大文件数:
			     hive.exec.max.created.files = 100000 (默认值,可修改,在hive.site中修改) 
	
	2. 永久 :修改hive-site.xml
	
常用操作:
	1.测试分区表的使用(严格模式下测试 partition.mode = strict)
	    1.1 创建一张带有分区的表:
		    student
			    id name age
				分区(静态分区是在创建时已经指定分区了)
			    year 
				month 
				day 
			建表语句,很多内容都使用默认	
			$hive> create table if not exists student (id int,name string,age int) partitioned by (year int,month int,day int) row format delimited fields terminated by ',';
			
			
		1.2 加载数据时,有分区时需要指定加载数据到哪个分区,进行分区指定。此时是加载进两个分区
		    load data local inpath '/home/centos/data/student.txt' into table student partition(year=1998,month=7,day=31);
		    load data local inpath '/home/centos/data/student.txt' into table student partition(year=1999,month=7,day=31);
		1.3 使用动态分区语句报错:
			 insert into table student partition (year,month,day) select id,name,age,year,month,day from test_student;
    
	2.测试动态分区(非严格模式下测试 partition.mode = nonstrict)	
	    打开非严格模式:
		    set hive.exec.dynamic.partition.mode = nonstrict;
		建立表:
		    create table test_student(id int,name string,age int,year int,month int,day int) row format delimited fields terminated by ',';
		加载数据:
		    load data local inpath '/home/centos/data/p_stu' into table test_student;
		执行动态分区语句(通过字段形式在执行过程中改变分区):
		    insert into table student partition (year,month,day) select id,name,age,year,month,day from test_student;
			
			根据其他表中的字段,来确定分区。
			
	3.半自动化分区:
	    insert into table student partition (year=2002,month,day) select id,name,age,month,day from test_student;
	
	4.分区后的检索
	    将分区看做字段进行条件查询
	    select * from student where year = 1998;  ->会将1998的列出来
		select * from student order by year;      ->会根据年进行整体排列

=======================================================================4.15

十七.分桶表


Map Reduce:
    1. partition 3  ->分区
    2. split        ->切片  
    3. map          ->映射 
    4. shuffle      ->分发     
    5. reduce

    reduce 个数 = partition 分区的个数 :将文件按照分区数物理切割

桶表:hive中的桶表就相当于Hadoop中mapreduce的分区,分区(hive中分桶)数量等于文件数。

1.建立一张桶表:
    create table stu2 (sid int,sname string,sex string,age int,dept string) clustered by(sid) into 3 buckets row format delimited fields terminated by ',';
2.数据插入的三种方式:
    数据准备
        stu2.txt
        -------------------
        1,xiaoming,男,18,1
        2,xiaowang,男,18,1
        3,xiaoli,男,18,1
        4,xiaohong,女,19,2
        5,xiaolan,女,19,2
        6,xiaolv,女,19,2

    2.1 load data local inpath '/home/centos/data/stu2.txt' into table stu2;
        load data 这种方式不分桶,只是物理复制。
    2.2 insert into .. values : 不推荐
	
        由于每次insert操作,都会创建一个桶文件的copy文件(不会影响原数据文件),所以insert操作(只添加一条记录)会创建多个桶文件,不推荐使用。
    2.3 insert into table .. select ..
   
        hive属性设置:
        $hive>set hive.enforce.bucketing = true;  -> 强制分桶
        $hive>set mapreduce.job.reduces = 3;      -> 设置reduce个数

        建表:
        create table stu3 (sid int ,sname string,age int) clustered by(sid) into 3 buckets row format delimited fields terminated by ',';
      sorted by(sid asc) 
        测试:
        $hive> insert into table stu3 select sid,sname,age from stu2;
		    所有的数据不会分入不同桶文件
		$hive> insert into table stu3 select sid,sname,age from stu2 distribute by sid sort by sid asc;
		    distribute by sid 保证数据分桶
			sort by sid asc 保证桶内有序
			
    分桶逻辑:
	    bucket: 3
		sid % 3 = 0  -> bucket 1
		        = 1  -> bucket 2
				= 2  -> bucket 3
				
		[centos@master data]$ hdfs dfs -cat /root/hive/warehouse/db1.db/stu3/000000_0
		6,xiaolv,19
		3,xiaoli,18
		[centos@master data]$ hdfs dfs -cat /root/hive/warehouse/db1.db/stu3/000001_0
		4,xiaohong,19
		1,xiaoming,18
		[centos@master data]$ hdfs dfs -cat /root/hive/warehouse/db1.db/stu3/000002_0
		5,xiaolan,19
		2,xiaowang,18
		
【桶表总结】:
    1. clustered by    指定分桶所用列
	   into n buckets  指定分桶的个数
	   分桶的逻辑:
	   hive对分桶的字段(key)的hash值与bucket个数进行取余操作(hash%bucketNum),
	     从而可以保证数据均匀的随机的分布在所有的bucket文件中。
	2. sorted by       指定桶文件的排序规则
	
	3. 桶 = mapreduce 分区,完全相同。【桶文件的个数 = reduce的个数】
	
	4. hive中的分区和分桶有什么区别?
	    分区:
		指的数据仓库中表目录下的子目录。每个目录下面都放数据文件,通过文件夹名称作为条件查询,
		可以查询到某个文件夹下的内容,但是这个文件夹本身与数据没有任何的联系。
		分桶:
		按照分桶指定的字段(hash值)进行分桶,将原本应该出现的特别大的数据文件分割为多个小数据文件。

十八.hive排序


1. order by : 全局排序:所有的数据传入一个reduce,在数据量大的情况下,将会花费大量的时间
    $hive> set hive.mapred.mode = nonstrict;
	$hive> select * from t1 order by id;
2. sort by  : 非全局排序:数据进入reduce之前进行排序,只能保证每个reduce输出有序,不能保证全局有序。
    $hive> set mapred.reduce.task = 3;
	$hive> select * from stu3 sort by sid;
3. distribute by : 可以控制map的输出在reduce如何划分,可以按照指定字段将数据划分到不同reduce(桶文件)中,
                    与group by,distribute by控制reduce如何处理数据,sort by控制reduce如何排序。
	
	$hive> select * from stu3 distribute by sid sort by sid;
4. cluster by : distribute by + sort by ;
    [限制条件] : 当distribute by 和sort by 处理字段相同的时候,可以使用cluster by 来代替distribute by和sort by。					

=========================================================4.17

十九.hive变量:


变量的声明
	$hive> hive --define key=value
	$hive> select * from student where name = ${key}

二十.hive命令行中执行hadoop命令


centos : $> hadoop fs -lsr /
		 $> hdfs dfs -lsr /
		 
hive   : $hive> dfs -lsr /

二十一.hive表的数据类型与文件格式:


[数据类型]
---------------------
	数据类型	长度
	tinyint 	1byte     -- 字节类型
	smallint    2byte     -- 短整数类型
	int         4byte     -- 整数类型
	bigint      8byte     -- 长整形

	float       4byte     -- 单精度浮点型
	double      8byte     -- 双精度浮点型
	
	string                -- 字符序列
	boolean               -- 布尔类型
	
	binary                -- 字节数组
	timestamp             -- 全类型 (整数、浮点数、字符串)

[复杂(集合)数据类型]
	数据类型        描述                       用法                 实例
	---------------------------------------------------------------------------
	struct          类似于Java中的对象         字段.属性名            
	map             键值对                     字段[key]				  
	array           数组                       字段[下标]
	
	struct实例:
		1. 创建表
			create table t02 (id int , name string , s1 struct) 
			row format delimited fields terminated by ',' 
			collection items terminated by ':';   -> struct字段的分隔符。
		2. 准备数据
			t02.txt
			---------------
			1,xm,xm:18
			2,xw,xw:18
		3. 加载数据
			load data local inpath '/home/centos/data/t02.txt' into table t02;
		4. 查询struct属性
			做为列
				select id,name,s1.sname from t02;
			运行结果:
				1 xiaoming xm
				2 xiaownag xw	
			作为条件
				select id,name from t02 where s1.sname = 'xm' and s1.sage > 18;
			运行结果:
			       1 xiaoming
			
	map实例:
		1. 创建表 
			create table t03 (id int , name string , m1 map) 
			row format delimited fields terminated by '\t'  -> 指定字段的分隔符为tab
			collection items terminated by ','   -> 指定map集合中元素的分割符
			map keys terminated by ':';			 -> 指定map集合中元素的key与value的分隔符
		2. 准备数据
			t03.txt(1)
			 1 xm grade:3,class:5
			 2 xw grade:2,class:4
			t03.txt(2)
			   3 xh grade:3,class:5,group:2
			   4 xv grade:2,class:4
		3. 加载数据
			load data local inpath '/home/centos/data/t03.txt' into table t03;
		   运行结果(1):
			1 xm {'grade':3,'class':5}
			2 xw {'grade':2,'class':4}
		   运行结果(2):
			1 xm {'grade':3,'class':5}
			2 xw {'grade':2,'class':4}
			3 xh {'grade':3,'class':5,'group':2}
			4 xv {'grade':2,'class':4}
		4. 查询数据
			 select id, name,m1['grade'] as grade , m1['class'] from t03;
		   运行结果:
			1 xm 3 5
			2 xw 2 4
			3 xh 3 5
			4 xv 2 4
			 select id,name from t03 where m1['grade'] = 3 and m1['class'] = 5;
	       运行结果:
			1 xm
			3 xh   
	array实例:
		1. 创建表
			create table t04 (id int ,name string , a1 array)
			row format delimited fields terminated by ','
			collection items terminated by ':';
		2. 准备数据
			t04.txt
			--------------
			1,xm,java:jsp:hadoop
			2,xw,c:c++:asp:ios
		3. 加载数据
			load data local inpath '/home/centos/data/t04.txt' into table t04;
		4. 查询数据
			select id,name,a1[0],a1[1] from t04 where a1[2] = 'hadoop';
           运行结果:
                         1 xm java jsp
           
[数据文件格式]
	1. textfile
	--------------------
		hive默认的数据格式,导入数据时会将数据文件原封不动拷贝到hdfs上而不进行任何的处理。
		查看数据比较方便,磁盘开销大、数据解析时开销大。
	2. sequencefile
	--------------------
		二进制文件,以key value对的形式将数据序列化到数据文件中。
		存储方式: 按行存储
		可分割、可压缩(block压缩)
		sf文件是与hadoopAPI中的mapfile相互兼容。
		在进行大量分块操作时,按行存储的方式执行效率不高
	3. rcfile
	--------------------
		存储方式:将数据按行分块,每块按列存储
		压缩快 列读写快。(行转列)
		读取记录时涉及到的块是最少的
		在读取全部数据时,跟sequencefile相比没有明显的效率提升。
	4. orcfile
	--------------------
		存储方式:行转列
		压缩快,列读取快
		效率比rcfile高一些,其他特点与rcfile相同,相当于rcfile的升级版
		
	测试: 
		1. 创建三张表,分别使用不同的文件格式
			create table t_01(id int,name string) row format delimited fields terminated by ',' stored as textfile;
			
			create table t_02(id int,name string) row format delimited fields terminated by ',' stored as sequencefile;
			
			create table t_03(id int,name string) row format delimited fields terminated by ',' stored as orcfile;
			
		2. 向三张表中分别导入数据。
			
			insert into table t_01 select id,name from student group by id,name ;
			insert into table t_02 select id,name from student group by id,name ;
			insert into table t_03 select id,name from student group by id,name ;
			
			insert select 与load不同之处:i s语句转成mr作业,load直接拷贝
			
			
		3. 观察三张表在hdfs上面数据文件的存储格式:
			$> hdfs dfs -lsr /
				drwxrwxrwx   - centos supergroup          0 2020-04-17 15:45 /root/hive/warehouse/db1.db/t_01
				-rwxrwxrwx   1 centos supergroup         67 2020-04-17 15:45 /root/hive/warehouse/db1.db/t_01/000000_0
				drwxrwxrwx   - centos supergroup          0 2020-04-17 15:46 /root/hive/warehouse/db1.db/t_02
				-rwxrwxrwx   1 centos supergroup        226 2020-04-17 15:46 /root/hive/warehouse/db1.db/t_02/000000_0
				drwxrwxrwx   - centos supergroup          0 2020-04-17 15:47 /root/hive/warehouse/db1.db/t_03
				-rwxrwxrwx   1 centos supergroup        347 2020-04-17 15:47 /root/hive/warehouse/db1.db/t_03/000000_0
				
			$> hdfs dfs -cat /root/hive/warehouse/db1.db/t_01/000000_0
				
			$> hdfs dfs -cat /root/hive/warehouse/db1.db/t_02/000000_0
			
			$> hdfs dfs -cat /root/hive/warehouse/db1.db/t_03/000000_0
			

二十二.数据操作


1.数据导入
    load data
        动态分区导入:
		
    insert into .. select

    creat table .. as select

2.数据导出
    将表的文件夹从hive中下载到本地(不加local,导入到hdfs上)
    insert [overwrite] local directory 'path' select ...
	例:$hive> insert overwrite local directory '/home/centos/data/student' select id,name,age from student;

二十三.在hive中何时不会hql转换为mr执行


1. 全表查询: 
    select * from student;
2. 分页查询:
    select * from student limit 0,10;
3. 如果在条件查询时,有时会将查询语句转成mr
    hive.fetch.task.conversion = minimal         -> 所有查询都会转换为mr
                                 more(默认)    -> 尽量减少查询转为mr
分区表的查询可以不转为mr;

二十四.hive常用函数:


1. 数学函数
	round(double d,int n)  四舍五入  n是小数位数 

	floor(double d)  返回小于d的最大整数
		 
	ceil(double d)  返回大于d的最小整数

	rand(int s)  返回随机数,s是随机因子

	bin(int d)  计算二进制d的string值
	
2. 日期函数
	to_date(string time)  将字符串日期转成date类型
    select to_date('2020-4-22 10:50:02');
	current_date  返回当前日期
	year(date)	 返回date参数中的年
	month(date)  返回date参数中的月
	day(date)    返回date参数中的日
	
	weekofyear(date)  返回date是该年的第几周
	datediff(date1,date2)  返回date1和date2相差的天数
	select datediff(current_date,to_date('2020-3-12'));
	date_add(date1,int1) 在date1天加int1的天数
	date_sub(date1,int1) 在date1天减int1的天数
	months_between(date1,date2)  返回date1和date2之间相差月数
	last_day(date1)  返回date1所在月份的最后一天
	next_day(date1,day1)  返回date1下一周的day1的日期
	trunc(date1,format)  日期截断,根据format 2020-4-22 'yyyy-mm'  ->返回2020-4-1
	
3. 选择函数
	if(boolean,t1,t2);  如果boolean表达式成立,返回t1,不成立返回t2
	    $hive> select id,if(age>18,1,0) as flag from student;
	case when _boolean then _value end;   _boolean成立,则返回_value
	    $hive>select id,name,case when age>18 then '>18' else '<=18' end a from student;
	isnull(v) : 如果v为null,则返回true,不为null则返回false
	coalesce(v0,v1,v2)  返回参数列表中的第一个非空值,如果所有值都为null,则返回null
	
4. 字符串函数
	length(str) 返回str的长度
	concat(str1,str2) 拼接str1和str2
	    $hive>select concat('abc','sdf');
	concat_ws(sep,str1,str2) 以sep作为分隔符对str1和str2进行拼接
	    $hive>select concat_ws(',','sdf','zxc');
	lower(str) 将str转成小写 
	upper(str) 将str转成大写
	repeat(str,int1)   str字符串重复int1次后的字符串
	    $hive>select repeat('adh',1);
	reverse(str) 字符串反转
	rpad(str,len,pad) 以pad字符右填充str,至len长度
	    $hive>select rpad('hello',8,'a');
	split(str,sep) 以sep作为分割符分割str,返回array
	    $hive>select split('hello,a1,a2',',');
	substr(str,index,int1) 在index位置起截取int1长度的字符串 
	    $hive>select substr('hello',2,3);
	replace(str1,str2,str3)  在str1中,将str2替换为str3
	    $hive>select replace('hello','he','hy');
		
5. 表生成函数
	explode(array)  ->列转行操作,与聚合函数是相反的
	    $hive>select explode(array(1,2,3));
	    $hive>select explode(split('h1,h2,h3',','));
	explode(map)
	    $hive>select explode(map(1,'a',2,'b',3,'c'));

6. 聚合函数
	count(*/col) 统计行数
	avg(col)	统计平均值
	sum(col)	统计和
	min(col)	统计最小值
	max(col)	统计最大值
	
	练习2:
使用JSP/SSH框架 访问hive数据仓库,并将数据展示到web页面中。
JDBC + HiveServer2

二十五.hive中事务的使用


1.hive中的事务是如何实现的
2.hive数据仓库与关系型数据库事务的实现有什么差异
3.hive中事务应用场景
4.hive事务与关系型数据库的使用区别。

事务ACID 四大特征:
A.原子性
C.一致性
I.隔离性
D.持久性

关系型数据库处理并发事务时几个问题:
事务并发问题的解决方式:
    最高事务隔离级别: 串行化(将并发操作 加入互拆锁,使并发操作 变为串行化操作)

hive 1.x 版本后加入了对事务的支持:
     关系型数据库(data) -> 非关系型数据库  的操作需要事务支持的
  

事务的实现:
	预写日志 :保证原子性和持久性(原子性:要么都成功要么都失败; 持久性:将操作写入硬盘中)
	锁(lock) :互拆锁: 占用某资源时,为该资源加锁。(隔离性)
         【注意】:锁在并发环境中通过读写锁保证操作的互斥性,根据隔离级别的不同,锁的应用也不同。
	->
	->  data  -> -> ->
	->

在hive的metaData库中有专门一张表来存储锁的数据(hive_locks)
$hive> show locks;


在hive中事务的使用准备工作:
---------------------------------
	在hive默认环境下,事务支持选项是关闭的。
	hive.support.concurrency = true (打开事务支持)
							   [false (关闭事务支持)] 
 
	hive.enforce.bucketing = true (桶表事务支持,hive2.0后的默认配置)
 
	hive.exec.dynamic.partition.mode = nonstrict (非严格模式,使用事务时打开非严格模式)
                                       [strict (严格模式)] 
 
	hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager  
					  [org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager(默认配置)] 

	hive.compactor.initiator.on = true (事务元数据对象初始化)
								  [false(默认配置)]
 
	hive.compactor.worker.threads =  1
									[0(默认配置)]
 
	如果使用beeline来操作hive
		hive.support.concurrency = true
 
 
hive中使用事务注意事项
--------------------------------------
	1. begin,commit,rollback在hive中暂时不支持,所有的作业自动提交
	2. 数据格式为ORC格式
	3. 表必须是桶表
	4. hive的事务支持默认关闭,在使用是需要手动打开
	5. hive的事务管理器必须设置为 org.apache.hadoop.hive.ql.lockmgr.DbTxnManage,不然无法支持hive的事务工作。
	6. hive目前支持快照级别的事务隔离。
	7. 已有的zookeeper管理hive锁的内存与Hive事务内存不冲突的。
		-zookeeper
		-hbase
		-flume kafka storm ….
		-spark(scala) -> 生态圈
    8.load data 语句在目前hive中不支持事。

二十六.操作:


$hive>insert into t_01 values (10,‘xiaofang’);

hive事务操作
------------------------------
	1.hive事务支持的配置:
	[客户端]
	set hive.support.concurrency = true;
	set hive.exec.dynamic.partition.mode = nonstrict;
	set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
	 
	[服务端]
	set hive.compactor.initiator.on = true;
	set hive.compactor.worker.threads = 1;

    2.创建一张测试表:
    $hive>create table test_txn(id int,name string) clustered by(id) into 2 buckets row format delimited fields terminated by ',' stored as orc tblproperties("transactional"="true","compactor.mapreduce.map.momory.mb"="2048","compactorthreshold.hive.compactor.delta.num.threshold"="4","compactorthreshold.hive.compactor.delta.pct.threshold"="0.5");
    解释:
		1."transactional"="true":指定该表为事务性表
		2."compactor.mapreduce.map.momory.mb"="2048":指定map作业可申请的内存大小为2kb(紧缩map作业)
		3."compactorthreshold.hive.compactor.delta.num.threshold"="4":增量目录轻度合并
		4."compactorthreshold.hive.compactor.delta.pct.threshold"="0.5"):如果增量文件与基础文件大小比率超过0.5,就会触发深度合并

二十七.操作:


create table tx1(id int,name string) row format delimited fields terminated by ‘,’;
load data local inpath ‘/home/centos/data/tx.txt’ into table tx1;
insert

	3.对事务进行事务性操作(update、delete)
		对非事务性表进行update
		    $hive>update student set name='xiaolv' where id=4;
		对事务性表进行update
			$hive>update test_txn set name='xiaohei' where id=4;
		对事务性表进行delete	
		    $hive>delete from test_txn where=4;
			
			$hive>dfs -lsr /root/hive/warehouse/db1.db/test_txn;
				drwxr-xr-x   - centos supergroup          0 2020-05-06 23:54 /root/hive/warehouse/db1.db/test_txn/delta_0000001_0000001_0000
				-rw-r--r--   1 centos supergroup        668 2020-05-06 23:54 /root/hive/warehouse/db1.db/test_txn/delta_0000001_0000001_0000/bucket_00000
				-rw-r--r--   1 centos supergroup        672 2020-05-06 23:54 /root/hive/warehouse/db1.db/test_txn/delta_0000001_0000001_0000/bucket_00001
		观察桶表的hdfs的目录结构
		多出来一个隐藏文件夹:预写日志(临时目录)
		桶目录中:每一次事务性操作都会创建一个操作目录,在此目录下而存放数据文件
		4.作业:
		并发性的事务操作的特点:
		并发执行=C     串行执行=S     不支持=N
                                                  Hive
	操作	                关闭Concurrency	        开启Concurrency	        开启Transaction	Mysql
	并行select	 	 	 	 
	并行insert	 	 	 	 
	insert、select并行	 	 	 	 
	select、insert并行	 	 	 	 
	delete	 	 	 	 
	update	 	 	 	 
	同时delete一条数据	 	 	 	 
	同时delete多条数据	 	 	 	 
	同时update一条数据	 	 	 	 
	同时update多条数据	 	 	 	 
	update同时select该条记录	 	 	 	 
	delete同时update相同数据	 	 	 	 
	delete同时update不同数据	 	 	 	 
	delete同时执行select操作	 	 	 	 

二十八.hive的优化


0. 执行计划
    $hive> explain HQL;查看HQL语句的执行计划,有些stage是可以并行的,hive中默认一次只能执行一个stage,stage之间存在依赖关系。
1. fetch抓取
    $hive> set hive.fetch.task.conversion = [more]  -> 某些简单查询不经过Mr。(默认)
	                                        minimal -> 在where和limit时 不经过Mr 
                                             none   -> 无论执行什么HQL语句,都会转换为Mr。                                        
2. 开启本地模式
    hive中默认分布式模式,我们可以通过配置将hive设置为本地模式,在做测试时,执行效率要高于分布式模式。
    
	$hive> set hive.exec.mode.local.auto = [false]  -> 分布式模式
                                            true    -> 本地模式
											
    $hive> set hive.exec.mode.local.auto.inputbytes.max = [134217728];  启动本地模式的最大的文件输入大小为128M
        注意: 在修改时,一定是2的幂计算的结果(1,2,4,8,16,32,64...)
		
    $hive> set hive.exec.mode.local.auto.input.files.max = [4];  本地模式的最大任务数为4

3. 合理利用文件存储格式: 创建表时,尽量使用orc数据格式(列式存储)。

4. 压缩存储:
		hive的数据压缩格式 等同于 hadoop的数据压缩格式。
			
		map reduce 性能瓶颈:
            1.磁盘IO
                数据量越大,磁盘IO次数就会越多。可以通过压缩数据达到减少磁盘IO次数的目的。
                
				压缩格式:
				    zlib:   默认压缩格式                                                        -> org.apache.hadoop.io.compress.DefaultCodec
					gzip:   不可拆分,是hadoop自带的,压缩比率高,压缩速度比较快                -> org.apache.hadoop.io.compress.GzipCodec
					lzo:    可拆分,(是hadoop自带的)需要手动安装,压缩率比较高,压缩速度很快  -> org.apache.hadoop.io.compress.lzo.LzoCodec
					snappy: 不可拆分,(是hadoop自带的)需要安装,压缩率比较高,压缩速度很快    -> org.apache.hadoop.io.compress.SnappyCodec
					bzip2:  可拆分,是hadoop自带,压缩比率最高,压缩速度慢                      -> org.apache.hadoop.io.compress.BZip2Codec    
            
			2.网络IO
			
		如何选择压缩方式:
		    1. 是否支持拆分(切割 -> split)
		    2. 压缩比率
		    3. 压缩(解压缩)速度
		
		使用压缩格式:
		    设置数据文件压缩格式:hive.exec.orc.default.compress = ZLIB;
			
			1. Job输出文件按照block以gzip的方式进行压缩:
			    $hive> set mapreduce.output.fileoutputformat.compress = true; 打开压缩支持(默认打开)
				$hive> set mapreduce.output.fileoutputformat.compress.type = block; //record按照block压缩
				$hive> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.GzipCodec; -> 指定压缩格式
				       默认为org.apache.hadoop.io.compress.DefaultCodec
			2. map的输出结果是gzip:
				$hive> set mapred.map.output.compress = true; //打开压缩支持,map输出时进行压缩
				$hive> set mapreduce.map.output.compress.codec = org.apache.hadoop.io.compress.GzipCodec; //map输出的压缩格式
				       默认为org.apache.hadoop.io.compress.DefaultCodec
			3. 对hive的输出结果以及中间步骤都进行压缩(包括1,2): 连用
				$hive> set hive.exec.compress.output = true; //设置mapreduce的压缩
				$hive> set hive.exec.compress.intermediate = true; //启用mapreduce压缩
5. 表优化
	1. join 多表查询:
		1.1 小表与大表join操作:
			MySQL :
			--------------------
				left : 大表 join 小表
				right : 小表 join 大表
			Hive:
			--------------------
				- 将key相对分散的,并且数据量小的表放在join左边,这样做可以减少发生内存溢出的几率。
				  可以使用group语句让小表有限进入内存(map处理)。
				- 在hive2.0后,hive已对小表和大表的join操作进行了优化处理,join两边放大表或小表执行效率相差不大。
				
			[测试]:
				测试大表join小表和小表join大表这两种操作的执行效率。
				1. 建表
					$hive> create table big_table(id int,time int,uid string,keyword string,[click_num int,click_url string]) row format delimited fields terminated by ',';
					$hive> create table big_table(id int,time int,uid string,keyword string) row format delimited fields terminated by ',';
					$hive> create table small_table(id int,time int,uid string,keyword string) row format delimited fields terminated by ',';
					$hive> create table join_table(id int,time int,uid string,keyword string) row format delimited fields terminated by ',';
				  
				2. 载入数据
					1,10,1000,赵
					2,20,1001,李
					3,30,1011,孙
					4,40,1012,周
					5,50,1013,钱
					$hive> load data local inpath '/home/centos/data/' into table big_table|small_table;
				3. 关闭map join功能(默认是打开的)
				    $hive> set hive.auto.convert.join = false;
				4. 执行小表join大表
					$hive> insert overwrite table join_table select b.id,b.uid,b.keyword,b.click_num,b.click_url from small_table s join big_table b on b.id = s.id;
				5. 执行大表join小表
					$hive> insert overwrite table join_table select s.id,s.uid,s.keyword,s.click_num,s.click_url from big_table b join small_table s on s.id = b.id;
		1.2 大表与大表的join操作:
		    空key处理:
				1.空key过滤
					有时join操作会超时,这是因为某个key对应的数据量太大,而相同key所对应的数据会发送到相同reducer上面进行处理,从而导致内
					存不够。一般来讲这些key所对应的数据都是异常的数据,我们需要对这些数据进行过滤。
					create table null_id_table(id int,time int,uid string,keyword string,[click_num int,click_url string]) row format delimited fields terminated by ',';
					- 不过滤空key
						$hive> insert overwrite table join_table select n.* from null_id_table n left join small_table s on n.id = s.id;
					- 过滤空key 
						$hive> insert overwrite table join_table select n.* from (select * from null_id_table where id is not null) n left join small_table s on n.id = s.id;
				2.空key转换
					有时虽然某个key为空的数据很多,虽然key为null,但是其他字段是需要展示到join结果集中的。这时可以给key为null的字段赋予
					一个随机值,将数据均匀分布到不同reducer上面。(1.减少内存溢出的发生 2.一定程度的避免数据倾斜)
					
					- 设置reduce的个数:
						$hive> set mapreduce.job.reduces = 5;
					- 不转换空key
						$hive> insert overwrite table join_table select n.* from null_id_table n left join small_table s on n.id = s.id; 
					- 转换空key
						$hive> insert overwrite table join_table select n.* from null_id_table n left join small_table s on (case when n.id is null then concat('hive',rand()) else n.id end) = s.id;
		1.3 map端join操作:
	        在hive中如果不指定mapjoin,那么hive解析器将join操作转换成common join(在reduce阶段完成join,比较容易发生数据倾斜)。
			可以使用mapjoin将小表全部加载到内存中在map端进行join,从而避免在reduce端进行join操作(数据倾斜)。
			
			[测试]
			    1.开启mapjoin参数设置
				    $hive> set hive.auto.convert.join = true;
				2.设置大表阙值(hive默认25M以下的表为小表)
				    $hive> set hive.mapjoin.smalltable.filesize = 25000000;
				3.具体操作
				    3.1 执行小表join大表
					    $hive> insert overwrite table join_table select b.id,b.uid,b.keyword,b.click_num,b.click_url from small_table s join big_table b on b.id = s.id;
					3.2 执行大表join小表
					    $hive> insert overwrite table join_table select s.id,s.uid,s.keyword,s.click_num,s.click_url from big_table b join small_table s on s.id = b.id;
	
	2. group by
        在默认的情况下,Map阶段同一key的数据分发给同一个reduce,如果某个key对应的数据量过大就会产生数据倾斜。
        并不是所有的聚合操作都需要在reduce端完成,很多聚合操作都可以先在map端进行部分聚合,最后在reduce端得出最终结果。
        
        开启map端聚合参数设置:
        1.是否在map端进行聚合,默认为true
            $hive> set hive.map.aggr = true;
        2.在map端进行聚合操作的记录数目:
            $hive> set hive.groupby.mapaggr.checkinterval = 100000;
        3.数据倾斜时,进行负载均衡(默认关闭)		
            $hive> set hive.groupby.skewindata = true;
	
	3.count(distinct) 去重操作
		count(distinct)是为了防止数据量大的情况下,某一个reduce负载过大,导致整个job难以完成。
		1.执行去重id查询
		    $hive> select count(distinct id) from big_table;
		2.采用group by去重id
		    $hive> select count(a.id) from (select id from big_table group by id) a;
	
	4.笛卡尔积
        当hive设置严格模式时,不允许在HQL语句出现笛卡尔积,hive对笛卡尔积支持较弱。
        如果需要的话,可以设置reduce个数为1,不打开严格模式。
	
	5.行列过滤:
		列处理:
			在select中,只查询需要查询的列,尽量减少分区过滤,少用select *。
		行处理:
			在区分剪裁中,当使用外关联时,如果将副表的过滤条件写在where后面,name就会先全表管联,之后再过滤。
			[测试]
				先关联两张表,再用where条件进行过滤:
					select s.id from big_table b join small_table s on b.id = s.id where id<10;
				通过子查询后,再进行表关联
					select b.id from big_table b join (select id from small_table where id<10)s on b.id = s.id;
	
	6.动态分区:
		参数设置:
			1.打开动态分区:
			    $hive> set hive.exec.dynamic.partition = true;
			2.设置为非严格模式
			    $hive> set hive.exec.dynamic.partition.mode = nonstrict;
			3.在所有的Mr节点上,最大可创建的动态分区数:
			    $hive> set hive.exec.max.dynamic.partitions = 1000;
			4.在每个执行的Mr节点上,最大可创建的动态分区数:
			    $hive> set hive.exec.max.dynamic.partitions.pernode = 100;
			5.在整个Mr job 中,最大可创建的文件数:
			    $hive> set hive.exec.max.created.files = 100000;
			6.当有空分区生成时,是否抛出异常,一般是不需要进行设置的。
			    $hive> set hive.error.on.empty.partition = false;
		[测试]
			1.创建分区表
			2.加载数据到分区表
			3.创建目标分区表
			4.进行动态分区的优化参数设定
			5.通过insert..select完成分区
			6.查看分区表的分区情况:
				$hive> show partitions tablename;
	
	7.in/exists语句优化
		在hive中对in语句和exists语句有替代方案: left semi join
			使用in:
				$hive> select a.id,a.name,from a where a.id in (select b.id from b);
			使用exists:
				$hive> select a.id,a.name,from a where exists (select id from b where a.id = b.id);
			替代方案
				$hive> select a.id,a.name,from a left semi join b on a.id = b.id;
	
	8.排序选择:
		1.order by          :全局排序,缺陷是只能使用一个reduce。
		2.sort by           :单机排序,单个reduce进行排序。
		3.distribute by     :分桶,保证同一个字段的值存在一个结果文件中。一般与sort by连用,保证每个reduce task结果是有序的。
		4.cluster by        :对同一个字段分桶并排序,不能与sort by 连用。= distribute by + sort by.
	
	9.multi-group by : 4可以使用multi-group by 减少mr数量
	
	10.合理使用分桶: bucket		
6. 数据倾斜					
    1.调整map数
		- Map数决定因素(split切片数量)
			[问题]Map的数量在hadoop中是根据什么决定的?
			[答]在通常情况下,job是根据输入目录产生多个map任务
				1.input的文件的总个数
				2.input的文件大小
				3.集群设置的文件的块大小
					
				一个mr job的MapTask数量是由输入切片InputSpilt决定。FileInputFormat.getSplit()可获取mr job的切片数。
					在hadoop中常用的配置:
					    -dfs.blocksize=128M ->HDFS默认的数据块大小
					    -mapreduce.input.fileinputformat.split.minsize=1 ->最小切片大小
					    -mapreduce.input.fileinputformat.split.maxsize=256M->在hive中设置mr作业中的最大切片大小
			mr的切片大小的计算公式:
				long splitSize=Math.max(minSize,Math.min(maxSize,blockSize));
		- 小数据文件处理(hadoop不擅于处理大量的小数据文件)
			配置:
				1.$hive>set hive.merge.mapfiles=true;               -> 在map任务结束时合并小文件。
				2.$hive>set hive.merge.mapredfiles=false;           -> 设置为true: 在mapreduce任务结束时合并小文件。
				3.$hive>set hive.merge.size.pre.task=256*1000*1000  -> 256M: 合并文件的大小
				4.$hive>set mapred.max.spilt.size=256*1000*1000;    -> 每个map的最大切片大小(hive2中内置)
				5.$hive>set mapred.min.spilt.size.pre.node=1;       -> 一个节点中spilt的最小值(hive2中内置)
				6.$hive>set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFoemat; -> 执行map前进行小文件合并
		- 复杂的数据文件处理
				- input的文件都很大,任务逻辑复杂。在做以上操作时,map的执行效率会非常慢。在这时可以考虑增加map数量,来使每个map处理的数据量减少,从而提高任务的执行效率。
				- 增加map的方法:
					 根据切片数的计算公式,得出,只要修改spilt.maxsizeset mapreduce.input.fileinputformat.split.maxsize=64
	
	2.调整reduce个数:
		reduce数的决定因素?
			hadoop的分区数。
		hive中有一些属性确定reduce个数:
			配置:   
			2.1在hive中设置reduce个数      
				$hive>set hive.exec.reducers.bytes.per.reducer=256000000  -> 每个reduce任务处理的数据量。
				$hive>set hive.exec.reducers.max=1009                     -> 每个job的最大reduce个数。
			2.2在hadoop中设置reduce个数
				修改[mapred-site.xml]
				mapreduce.job.reduces=15;
			注意:reduce的个数不是越多越好,
				1.如果reduce个数过多,启动和初始化reduce时会消耗过多的时间和资源。
				2.如果reduce个数过多,就会产生很多的输出文件(往往都是比较小的文件),这些输出文件有时会做为下一个job的输入文件,输入文件如果为多个小文件时,就会降低下个job的执行效率。
			3.并发执行
			    Hive会将一个查询转化为多个阶段:map、reduce、抽样、合并、limit...在hive执行过程中可能还需要其他阶段。
				在默认情况下,hive一次只会执行一个阶段。但有时阶段与阶段之间是可以并发执行的,如果可以并发执行,整个job执行时间就可以缩短。
				    配置:
				         $hive>set hive.exec.parallel.thread.number=8;    -> 并发执行的任务数
				         $hive>set hive.exec.parallel=true;               -> 打开任务并行执行
			4.严格模式
			    防止用户做危险操作。
			5.jvm重用
			    JVM重用是hadoop的调优内容,对hive性能影响很大,特别是对很难避免的小文件处理的情况或者task特别多的情况。处理时间短,资源消耗大。
					hadoop中修改mapred-site.xml
					    mapreduce.job.jvm.numtasks=10
					注意:如果出现了比较严重的数据倾斜,整个的job执行时间变长。
		    6.执行计划
			    -查看简易计划
			        $hive> explain select * from usr;
			    -查看详细计划
			        $hive> explain extended select * from usr;
			7.推测执行
				根据自己经验,判断某些语句应该启用那些配置。

二十九.UDF:User define function 用户自定义函数


存储过程
	JDBC:
	Statement :SQL处理对象->静态sql语句的处理
	PreparedStatement :SQL预处理对象->动态SQL语句处理
	CallableStatement :SQL程序调用对象->外部程序(Java)调用DB中的过程
	 
函数
	函数往往在SQL中使用的。
	内置函数:
	 
用户自定义函数:
	在关系数据库中:
	 单独创建一个对象:create function function_name() …函数体…
	在hive中:
	 需要编写java程序 -> 将程序打包 -> 上传到hive/lib ->注册 -> 使用。
	 
1.function操作:
	-列出所有函数:show functions;
	-查看函数帮助:desc[ribe] function 函数名 ;
		$hive>desc function sum;
	-查看扩展帮助:desc[ribe] function extended 函数名 ;
		$hive>desc function extended sum;      
2.函数调用:
	select concat(col1,col2) as x from table;
	注意:在hive中函数的调用一定是在hql语句中使用,不能够单独调用
	$hive>concat('a','b')->错误
		$hive>select concat('abc','def');
	OK
	abcdef
	 
3.函数类型
	UDF:输入一行或多行,输出一个值(可以返回复杂对象 array map struct)
	    round()
	    abs()
	UDAF:(User define aggregate function)用户自定义聚合函数
	    一行或多行的n个列输入,输出一个值,一般是与group by联用
	    count()
		  $hive>select count(*) from t1;
	    avg()
	UDTF:(User define table function)表生成函数
	    n个输入,输出多行或多列
	    array()
		  $hive>select array(1,2,3);
	            OK
	            [1,2,3]
	    explode()
	      $hive>select explode(array(1,2,3));
				OK
				1
				2
				3
	    select explode(array(1,2,3)) as el from emp;
4.自定义函数
	【例】编写一个自定义函数,将字符串转换为日期格式。
	 
	1.依赖:hive-service
	pom.xml
	
	org.apache.hive
	hive-jdbc
	2.1.0
	
	 
	
	org.apache.hadoop
	hadoop-client
	2.7.3
	
	 
	
	org.apache.hive
	hive-exec
	2.1.0
	
	 
	
	org.apache.hive
	hive-service
	2.1.0
	
	 
	2.注解: 
	 
	@Description(name="xxx",value="yyy",extended="zzz")
	public class UDFxz extends UDF{
	try{
	SimpleDateFormat format=new SimpleDateFormat();
	format.applyPattern("yyyy/MM/dd HH:mm:ss");
	return format.parse(str);
	}catch(Exception ex){
	ex.printStackTrace();
	}
	return new Date();
	}
	}
	 
	ToDate.java:
	package com.sk;
	import org.apache.hadoop.hive.ql.exec.UDF;
	import org.apache.hadoop.hive.ql.exec.Description;
	import java.text.ParseException;
	import java.text.SimpleDateFormat;
	import java.util.Date;
	 
	@Description(
			//name函数起的函数名
			name="toDate",
			value="this is toDate function",
			extended = "ToDate('2020-6-4 10:50:10')->date obj or ToDate('1323345345334')"
	 
	)
	public class ToDate extends UDF {
		public Date evaluate(String str_date){
			//日期->字符串
			//SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			//String str=format.format(new Date());
			Date date=new Date();
			try{
				SimpleDateFormat format=new SimpleDateFormat();
				format.applyPattern("yyyy-MM-dd HH:mm:ss");
				date=format.parse(str_date);
			}catch(ParseException e){
				e.printStackTrace();
			}
			return date;
		}
	 
		public Date evaluate(long mil){
			Date date=new Date(mil);
			return date;
		}
	}
	 
	3.将函数打包成jar
	    idea:maven projects -> Lifecycle -> package -> 右键 ->run maven Build
	4.通过hive命令将jar添加至hive的类路径
	    $hive>add jar /home/centos/func/xxx.jar
	5.注册函数
	    $hive>create temporary function to_date as 'com.sk.xx.func.toDate'
	6.调用
	    1.add jar jar包路径
		  最常用的一种方式,每次开启hive时,自定义函数都需要重新注册
        2.hive-site.xml 
		  hive.aux.jars.path  -> file:///jarpath/jarname.jar
		3.hive安装目录下创建文件夹 auxlib 将jar放入
        4.hive-env.sh         -> export HIVE_AUX_JARS_PATH = jar path 			

1.创建项目,导入pom依赖
2.编写UDF程序
3.将UDF打包,并且将UDF的jar文件上传至linux
4.add jar
5.create temporary function 函数名 as '包名.类名'

你可能感兴趣的:(Hadoop,hadoop,hive)