一、hive简介
1. Hive 是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL ),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 HQL ,它允许熟悉 SQL 的用户查询数据。
2. Hive是SQL解析引擎,它将SQL语句转译成M/R Job然后在Hadoop执行(大部分的查询由 MapReduce 完成(包含 * 的查询,比如 select * from table 不会生成 MapRedcue 任务))。
3.Hive的表其实就是HDFS的目录/文件,按表名把文件夹分开。如果是分区表,则分区值是子文件夹名
二、hive架构
三、hive的metastore
1、metastore是hive元数据的集中存放地。metastore默认使用内嵌的derby数据库作为存储引擎
2、Derby引擎的缺点:一次只能打开一个会话(用户切换到不同目录下启动hive都会创建自己的MetaStore),不能多用户共享
3、使用Mysql作为外置存储引擎,多用户同时访问
四、hive与传统数据库
注意:由于 Hive 是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive 中不支持对数据的改写和添加,所有的数据都是在加载的时候中确定好的
五、hive的数据存储
Hive的数据存储基于Hadoop HDFS,没有专门的数据存储格式,存储结构主要包括:数据库、文件、表、视图,Hive默认可以直接加载文本文件(TextFile),还支持sequence file 、RC file,创建表时,指定Hive数据的列分隔符与行分隔符,Hive即可解析数据。
1、数据库
默认数据库"default",使用#hive命令后,不使用hive>use <数据库名>,系统默认的数据库。
可以创建一个新库hive > create database test_dw;
2、表
<1>Table 内部表
每一个 Table 在 Hive 中都有一个相应的目录存储数据。例如,一个表 test,它在 HDFS 中的路是user/hive/warehouse/test。 warehouse是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的数据仓库的目录,所有的 Table 数据(不包括 External Table)都保存在这个目录中。删除表时,元数据与数据都会被删除
例子:
创建表
hive>create table inner_table (key string);
加载数据
hive>load data local inpath '/root/inner_table.dat' into table inner_table;
<2>分区表
在hive中查询时一般会扫描整个表内容,会消耗很多时间做没必要的工作,因此出现了分区表!!
Partition 对应于数据库的 Partition 列的密集索引,在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中
例如:test表中包含 date 和 city 两个 Partition,则对应于date=20130201, city = bj 的 HDFS 子目录为/warehouse/test/date=20130201/city=bj
例子:
创建表
create table partition_table(rectime string,msisdn string) partitioned by(daytime string,city string) row format delimited fields terminated by '\t' stored as TEXTFILE;
加载数据到分区
load data local inpath '/home/partition_table.dat' into table partition_table partition (daytime='2013-02-01',city='bj');
增加、删除分区
alter table partition_table add(drop) partition (daytime='2013-02-04',city='bj')
<3>桶表
桶表是对数据进行哈希取值,然后与桶的数量取模。把数据放到对应的文件中。
创建表
create table bucket_table(id string) clustered by(id) into 3 buckets;(3个桶就是对应个文件)
加载数据
set hive.enforce.bucketing = true;
insert into table bucket_table select name from stu;
<4>外部表
(1)指向已经在 HDFS 中存在的数据,可以创建 Partition
(2)内部表 的创建过程和数据加载过程(这两个过程可以在同一个语句中完成),在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除;
外部表 只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据建立一个链接。当删除一个 外部表 时,仅删除该链接
创建表
hive>create external table external_table1 (key string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' location '/home/external';
六、创建表
1、create语法来创建
create external table employee( name string, salary float, subordinates array<string>, deductions map<string,float>, address struct<street:string,city:string,state:string,zip:int> ) row format delimited fields terminated by '\t' collection items terminated by ',' map keys terminated by ':', lines terminated by '\n' stored as textfile location '/data';
data数据的格式是这样的:
2、由一个表创建另一个表
create table test1 like test2;
3、由其他表查询创建表
create table test as select name from test1;
七、加载数据
1、内表加载数据
(1)创建表时加载
create table newtable as select col1,col2 from oldtable;
(2)本地数据加载
load data local inpath 'localpath' [overwrite] into table tablename;
(3)hdfs数据加载
load data inpath 'hdfspath' [overwrite] into table tablename;
注意:此操作是移动数据,hdfs上的数据将会移动到数据仓库
(4)由查询语句加载数据
insert [overwrite | into] table tablename
select col1,col2 from table where...........
2、外表数据加载
(1)创建表时指定数据位置
create external table tablename() .........location 'path';
(2)查询插入,同内表
注意:这个时候外表在数据仓库中是存在的,只不过这种方式对于外表来说没有什么意义!
3、hive分区表数据加载
(1)本地数据加载
load data local inpth 'localpath' [overwrite] into table tablename partition(pn=‘’);
(2)加载hdfs数据
load data inpath 'hdfspath' [overwrite] into table tablename partition(pn='')
(3)由查询语句加载数据
insert [overwrite] into table tablename partion(pn='')
select col1,col2 from table where.....
八、数据的导出方式
1、hadoop命令的方式
hadoop fs -get[text] /user/hive/warehouse/tablename/* /hive_data(本地路径)
2、通过insert的方式
insert overwrite [local] directory '/data' row format delimited fields terminated by '\t'
select col from tablename;
九、动态分区
*不需要为不同的分区添加不同的插入语句
*分区不确定,需要从数据中获取
1、必须设置的参数
set hive.exec.dynamic.partition=true;//使用动态分区
set hive.exec.dynamic.partition.mode=nostrick;//无限制模式,如果是strict,则比不有一个静态分区,且放在最前面
2、创建动态分区表及其插入数据
十、表属性操作
1、修改表名
alter table tablename rename to new_tablename;
2、修改列名
alter table tablename change column c1 c2 string;
3、 增加列
alter table tablename add columns (c1 string,c2 long);
4、修改分隔符
alter table tablename [partition(dt='xxxxx')] set serdeproperties ('field.delim'='\t');
5、修改location
alter table tablename [partition()] set location 'path';
十一、hive高级查询
1、order by
例子:select col1,col2 from tablename where...
order by col1,col2 [asc | desc];
注意:
* 可以有多列排序,默认按照字典排序
* order by为全局排序
* order by需要reduce操作,且只有一个reduce
mapreduce原理:
2、group by
*按照某些字段的值进行分组,有相同值放在一起(可以拿来去重操作)
样例:
select col1,[col2] from tablename
where....
group by col1,[col2]
注意:select 后面非聚合列必须出现在group by中
特征:
使用了reduce操作,受限于reduce数量,可以设置参数set mapred.reduce.tasks=n;
mapreduce原理:
3、Join
*join等值连接、left outer join左外连接、right outer join右外连接
例子:
select a.col,a.col2,b.col4 from a join b on a.col=b.col3
输出:
mapreduce原理:
4、mapjoin(join的优化操作,不走reduce)
*在map端把小标加载到内存,然后读取大表,和内存中的小表完成连接操作
优缺点:
优点:不消耗reduce资源
缺点:占用部分内存,因为每个map都会加载一次小表;生成较多小文件
配置参数:
select /*+mapjoin(n)*/ m.col,m.col2,n.col3 from m join n on m.col=n.col
mapreduce原理:
mapjoin的使用场景:
*有一张很小的表
*不等值连接操作
5、distribute by 和sort by
*distribute by分散数据
distribute by col,按照col列把数据分散到不同的reduce
*sort by排序
sort by col,对每个reduce局部对col排序
*样例
set mapred.reduce.tasks=3;//设置reduce数量为3
select col1,col2 from m
distribute by col1
sort by col1 asc,col2 asc;
*对比
mapreduce原理:
6、union all
*多个表的数据合并成一个表
样例:
select col
from(select a as col from t1
union all
select b as col from t2
)tmp;
十二、hive函数
1、内置函数
http://blog.csdn.net/wisgood/article/details/17376393
2、hive自定义函数
<1>UDF
例子:
写一个自定义函数,要求能对某一列的数据对某一个数比大小,返回True,false
package com.hive.hadoop; import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.io.Text; public class udfTest extends UDF{ public boolean evaluate(Text t1,Text t2) { if(t1==null||t2==null) return false; double d1=Double.parseDouble(t1.toString()); double d2=Double.parseDouble(t2.toString()); if(d1>d2) return true; else return false; } }
Hive执行add jar:
add jar /function.jar
Hive执行创建模板函数
create temporary function bigthan as ‘com.hive.hadoop.udfTest’
Hql中执行
Select col1,col2 ,bigthan(col2,5) from tablename;
<2>UDAF
例子:在上例的基础之上,统计一下大于基数的个数
package com.hive.hadoop; import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.parse.SemanticException; import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver; import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.io.LongWritable; public class CountBigThan extends AbstractGenericUDAFResolver{ //对参数进行判断 @Override public GenericUDAFEvaluator getEvaluator(TypeInfo[] paramaters) throws SemanticException { if(paramaters.length!=2) { throw new UDFArgumentTypeException(paramaters.length-1, "Exactly two argument is expected."); } return new GenericUDAFCountBigThanEvaluator(); } //这个类来处理逻辑 public static class GenericUDAFCountBigThanEvaluator extends GenericUDAFEvaluator{ private LongWritable result; private PrimitiveObjectInspector inputOI1; private PrimitiveObjectInspector inputOI2; //参数检查函数,每个阶段相关方法执行之前都会执行此函数 //map阶段:parameters长度与udaf输入的参数个数有关 //reduce阶段:parameters长度为1 @Override public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException { super.init(m, parameters); //最终结果变量 result=new LongWritable(0); //把原始参数转化一下,方便后面的通用类型转化 inputOI1=(PrimitiveObjectInspector)parameters[0]; if(parameters.length>1) { inputOI2=(PrimitiveObjectInspector)parameters[1]; } return PrimitiveObjectInspectorFactory.writableLongObjectInspector; } //此方法在map执行,用来缓存临时的值 @Override public AggregationBuffer getNewAggregationBuffer() throws HiveException { CountAgg agg=new CountAgg();//缓存一个long类型的变量(值是1),用来计数;需要重新定义一个类 //重置,需要再次使用的时候要重置为0 reset(agg); return agg; } @Override public void iterate(AggregationBuffer agg, Object[] par) throws HiveException { assert(par.length==2); if(par==null||par[0]==null||par[1]==null) return; double base=PrimitiveObjectInspectorUtils.getDouble(par[0], inputOI1); double tmp=PrimitiveObjectInspectorUtils.getDouble(par[1], inputOI2); if(base>tmp) ((CountAgg)agg).count++; } @Override public Object terminatePartial(AggregationBuffer agg) throws HiveException { result.set(((CountAgg)agg).count); return result; } @Override public void merge(AggregationBuffer agg, Object partial)//合并,这个partial是上面函数返回的对象 throws HiveException { if(partial!=null) { long p=PrimitiveObjectInspectorUtils.getLong(partial, inputOI1); ((CountAgg)agg).count+=p; } } @Override public Object terminate(AggregationBuffer agg) throws HiveException { result.set(((CountAgg)agg).count); return result; } //重置方法 @Override public void reset(AggregationBuffer CountAgg) throws HiveException { CountAgg agg=(CountAgg)CountAgg; agg.count=0; } //新建类 public static class CountAgg implements AggregationBuffer{ long count; } } }
Mode枚举类:
查看源码:
src\ql\src\java\org\apache\hadoop\hive\ql\udf\generic