一.简介:
① Hive是数据仓库 ;
② 将数据存放在 HDFS上, 元数据(MetaStroe)存放在 MySql上 (解决多用户共同操作Hive仓库问题);
③ 将 SQL 转换成 MapReduce ,在Hadoo集群上执行。但并非所有的 SQL都会转换成 MR ,eg. select * from tableName 就不需要,只需要把所有的数据都读出来就可以了读出10条也是如此
④ 使用 UDF 自定义函数 实现具体业务。
二. MySql安装 , 存储 MetaStore
问题:在哪里执行 hive 命令,在哪里创建元数据库。
hive-1.2.1目录下执行Hive:
[root@ming01 hive-1.2.1]# ls
bin derby.log hcatalog LICENSE NOTICE RELEASE_NOTES.txt
conf examples lib metastore_db README.txt scripts
hive> [root@ming01 TData]# ls
derby.log metastore_db student.txt
MySql 安装: 解决上述问题
1.删除Linux安装时,安装的 MySql 包
rpm -qa | grep mysql //查找 rpm 包
rpm -e mysql-libs-5.1.73-5.el6_6.x86_64 –nodeps //删除Linux 安装时 ,自动安装的 MySql 包
2.安装服务端:
rpm -ivh MySQL-server-5.5.48-1.linux2.6.x86_64.rpm
//安装MySql 服务端
3.安装客户端:
rpm -ivh MySQL-client-5.5.48-1.linux2.6.x86_64.rpm
//安装 Client
4.启动 MySql 服务:
service mysql start
5.设置root用户的密码:
/usr/bin/mysql_secure_installation (安装时提示的命令)
6.使用 mysql 进入命令行
mysql -rroot -proot
7.hive-site.xml 中配置 HIve 的元数据仓库为MySql
三.Hive 仓库操作: (本文不介绍Hive安装)
3.1.创建表(MANAGED_TABLE):
默认在 HDSF 中的位置:hdfs://ns1/user/hive/warehouse/t_user
①需指定分隔符,也可以使用默认)
②如果表被删除,数据也 表目录下 的数据也将被删除
hive> create table student(id int , name string)
> row format delimited fields terminated by '\t';
//向 Hive 中添加数据:(一般都是以文件的形式 Load)
load data local inpath '/cluster/TData/student.txt' into table student;
3.2.创建外部表(EXTERNAL_TABLE):
可以直接讲文件放入HDFS 上的目录,执行SQL语句时,会自动扫描。
默认在 HDFS 中的位置:hdfs://ns1/data
hive> create external table peoples (id bigint , name string , age int , description string )
> row format delimited fields terminated by '\t' location '/data' ;
hive> dfs -put /cluster/user.txt /data/a.txt ;
hive> dfs -put /cluster/user.txt /data/b.txt ;
3.3.创建分区表: (表字段 不能与分区字段重复)
//创建分区表(partition) —external 可以不要
hive> create external table t_company (id bigint , name string , size int ) partitioned by (province string ) row format delimited fields terminated by '\t' location '/company' ;
★★向分区表中加载数据的步骤:
★HDFS上文件:
①如果日志文件本身就分好了文件夹,则可以认为把分区创建好,使用External 外部表关联日志文件夹,
并修改 文件夹名称为 partittion=name形式,hive 命令中:添加分区信息到 MetaStore
②如果数据是个整体,并没有分文件(分区),则需要在 Hive 中创建 external 外部表指定该文件目录,
使用自动动态分区将数据导入 Hive 的 分区表中。
★本地文件:将数据 Load 到 Hive 普通临时表中,或HDFS,在通过自动动态分区 将数据导入到 分区表中。
3.3.1.方式一:Load 方式,手动指定分区(前提:一个文件对应一个分区内容)
如果数据要放到到 Hive 仓库, 则使用 Load 方式 ,就可以自动创建分区。
load data local inpath '/cluster/comp2.txt' into table t_company partition (province='Beijing') ;
load data local inpath '/cluster/comp.txt' into table t_company partition (province='Shenzhen') ;
3.3.2.方式二:Load方式+自动动态分区 (前提:所有的数据在一个文件中)态分区配置
①开启自动动态分区
set hive.exec.dynamic.partition.mode=nonstrict
②查询数据并插入分区表中
insert overwirte table t2 partition (var) select * from student ;
3.3.3. 方式三:手动创建分区目录,移动存在的数据到分区目录下
如果数据已经存在 , 则
①先创建分区目录
②再将 分区信息 写入 Hive 的元数据仓库
③将文件放到分区目录。
[root@ming01 TData]# hadoop fs -mkdir /company/province=Shenzhen
[root@ming01 TData]# hadoop fs -mkdir /company/province=Beijing
hive> dfs -mkdir /company/province=Hubei
hive> dfs -put /cluster/company.txt /company/province=Shenzhen ;
hive> dfs -put /cluster/company2.txt /company/province=Beijing ;
hive> alter table t_company add partition (province = 'Shanghai') location '/comp/province=Shanghai';
3.4.创建分桶表:
分桶表示例:
3.4.1.指定开启分桶
set hive.enforce.bucketing = true;
set mapreduce.job.reduces=4;
3.4.2.创建分桶表:(分桶前:必须先分簇,分桶字段必须事先排好序)
drop table stu_buck;
create table stu_buck(Sno int,Sname string,Sex string,Sage int,Sdept string)
clustered by(Sno)
sorted by(Sno DESC)
into 4 buckets
row format delimited
fields terminated by ',';
3.4.3.向分桶表中插入数据
注意:
①分桶表的数据只能使用 insert ,不能使用 load
②通过 select 查询出来的数据 ,必须 分簇,否则不能插入到 分桶表中
③cluster by(sno) 本身就带有 排序分簇的功能, 所以cluster 和 sort 不能同时存在
insert overwrite table student_buck
select * from student cluster by(Sno) sort by(Sage); 报错,cluster 和 sort 不能共存
方式一distribute by + sort by:
insert into table stu_buck
select Sno,Sname,Sex,Sage,Sdept from student distribute by(Sno) sort by(Sno asc);
方式二 cluster by:
insert overwrite table stu_buck
select * from student cluster by(Sno);
3.5.数据的导入与导出:
3.5.1 数据导入:
从 MySql —>> Hive(表已存在) : 具体查看 Sqoop ETL工具的使用
sqoop import --connect jdbc:mysql://192.168.1.10:3306/db --username root --password 12 --table trade_detail --hive-import --hive-overwrite --hive-table trade_detail --fields-terminated-by '\t'
从 MySql —->> Hive (表不存在)
create table result row format delimited fields terminated by '\t' as select * from t_user ;
导出数据到 本地文件或HDFS上(去掉local,则导出到HDFS文件系统)
insert overwrite local directory '/cluster/user_trade01'
row format delimited fields terminated by '\t'
select u.* , incomes , expenses , (incomes-expenses) surplus
from user_info u left join (
select account , sum(income) incomes , sum(expense) expenses
from trade_detail group by account ) t
on u.account = t.account ;
四.UDF函数的使用:(支持 多参数 传入 , 支持 evaluate 方法的重载)
4.1.编写UDF:
①创建JavaProject工程
②添加 Hive 的Jar 和 hadoop-common.jar
③创建Class ,继承 UDF
④实现 evaluate(…) 方法 , 方法的返回值使用 Text,因为以后程序要运行 MapReduce , 要在网络间传输数据。
⑤上传Jar包到 集群, 在 Hive 命令行:
4.2.Hive中使用UDF:
① hive> add jar /cluster/test_jar/ProvinceUDF.jar
② 创建临时函数:(只能在本次回话中使用, 退出后将不能
create temporary function getProvince as 'com.zym.udf.GetProvinceUDF' ;
③ 在 SQL 中使用:
select id , name , size , getProvince(province) from t_company;
4.3.销毁临时函数:
hive> drop temporary function getProvince;
hive> select id , name , getProvince(province) from t_company ;
OK
package com.zym.udf;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class GetProvinceUDF extends UDF{
//省份
public static Map provinceMap = new HashMap();
static{
provinceMap.put("Beijing", "北京");
provinceMap.put("Shanghai", "上海");
provinceMap.put("Hubei", "湖北");
provinceMap.put("Shenzhen", "深圳");
provinceMap.put("Guangzhou", "广州");
}
//输出结果
Text t = new Text() ;
//省份判断
public Text evaluate(Text province) {
String result = this.provinceMap.get(province.toString()) ;
if(result == null ){
result = "火星人" ;
}
t.set(result);
return t ;
}
//求和
public Text evaluate(Text a , Text b ){
String result = String.valueOf(Integer.parseInt(a.toString())+Integer.parseInt(b.toString())) ;
t.set(result);
return t ;
}
}