Hive Tutorial
数据单元:
分区:
每个表能够有一个或多个分区列,用来决定数据如何存储。分区不只仅是存储单元,并且容许用户按照条件组织分类数据,分区键列中每个不重复的值定义一个表的分区。分区能够极大的提升数据分析的速度。一个分区列就是一个伪列,因此分区列名能够自由设置,分区列的名称不能够和表中某一实际列的名称相同。node
Buckets(Clusters):
表中或每个分区中的数据能够被分隔成多个Buckets,分隔方式是依据表中的一些列的hash值,这些列能够用clustered by指定,这些列中相同的值会被存储到同一个文件中,而且能够经过sorted by 设置排序列和排序方式,这样的文件就称为bucket。表级别能够有bucket,分区下面也能够有bucket,这个时候分区和表的概念能够认为相同。bucket的特色:一个bucket文件中的数据某一列的值相同,而且能够依据某一列有序,前提是buckets的数目要和clustered by指定的列可能的取值数相同(我的理解)。apache
数据类型:
(包括各种型的长度,继承转化关系以及复杂类型构建)
https://cwiki.apache.org/confluence/display/Hive/Tutorialjson
内置操做符和内置函数:
在beeline命令行中查看:
show functions; 显示函数列表
describe function function_name; 函数的简单描述
describe function extended function_name; 函数的详细描述
str rlike regexp: Returns true if str matches regexp and false otherwise
经常使用函数:round floor ceil rand concat substr upper lower trim ltrim rtrim regexp_replace size from_unixtime to_date get_json_object
内置的聚合函数:
count(*):返回记录行总数,包括NULL值
count(expr): 返回expr不为null的行总数
count(distinct expr) 返会expr不为NULL而且值惟一的行的总数
avg(col)、avg(distinct col)
sum(col)、sum(distinct col)函数
Hive Sql的功能:
where语句过滤结果
select选择特定的列
表间的链接
对group by分组求值
把查询结果存储到一个表中
下载hive表中的内容到本地目录中
把查询结果保存到hdfs目录中
管理表和分区
在自定义的MR任务中,插入自定义的脚本oop
加载数据:
建立一个external表,指向hdfs中一个指定的位置,并提供数据行格式的信息,用户可使用hdfs的put或copy命令,把文件放到指定的那个位置。
举例:
若是/tmp/pv_2008-06-08.txt包含逗号分隔的行,要加载到page_view表中,能够依次执行:
CREATE EXTERNAL TABLE page_view_stg(...)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '44' LINES TERMINATED BY '12'
STORED AS TEXTFILE
LOCATION '/user/data/staging/page_view';性能
hadoop dfs -put /tmp/pv_2008-06-08.txt /user/data/staging/page_view大数据
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='US')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip
WHERE pvs.country = 'US';
这种方式适合hdfs中已经有的数据,须要使用hive来查询,所以须要向hive注册数据的元数据信息。ui
除此以外,还支持直接从操做系统中加载数据到hive表中:
LOAD DATA LOCAL INPATH /tmp/pv_2008-06-08_us.txt INTO TABLE page_view PARTITION(date='2008-06-08', country='US')
inpath参数取值:一个目录(目录下的全部文件被加载,不会递归子目录)、一个文件、通配符(仅仅匹配文件名)
从hdfs中的文嘉中加载数据到hive中:
LOAD DATA INPATH '/user/data/pv_2008-06-08_us.txt' INTO TABLE page_view PARTITION(date='2008-06-08', country='US')url
查询和插入数据:
简单查询:
INSERT OVERWRITE TABLE user_active
SELECT user.*
FROM user
WHERE user.active = 1;
全部的查询结果都会插入一个指定的表中,select * from users;查询结果在内部会写入到一些临时文件中。
分区查询:
查询时在where子句中,包含建立表时指定的分区字段做为条件。
链接join:
(left outer、right outer、full outer)
INSERT OVERWRITE TABLE pv_users
SELECT pv.*, u.gender, u.age
FROM user u JOIN page_view pv ON (pv.userid = u.id)
WHERE pv.date = '2008-03-03';
检查一个key在另一个表中是否存在 LEFT SEMI JOIN:
INSERT OVERWRITE TABLE pv_users
SELECT u.*
FROM user u LEFT SEMI JOIN page_view pv ON (pv.userid = u.id)
WHERE pv.date = '2008-03-03';
多表链接:
INSERT OVERWRITE TABLE pv_friends
SELECT pv.*, u.gender, u.age, f.friends
FROM page_view pv JOIN user u ON (pv.userid = u.id) JOIN friend_list f ON (u.id = f.uid)
WHERE pv.date = '2008-03-03';
链接时把包含大数据量的表放到右边,能够提升性能,仅支持等同链接。
聚合查询:
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count (DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;spa
使用多个聚合函数,每个聚合函数中,distinct后指定的列必须相同:
INSERT OVERWRITE TABLE pv_gender_agg
SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(*), sum(DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;
多表多文件插入:
FROM pv_users
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count_distinct(pv_users.userid)
GROUP BY pv_users.gender --查询结果插入到hive表中
INSERT OVERWRITE DIRECTORY '/user/data/tmp/pv_age_sum'
SELECT pv_users.age, count_distinct(pv_users.userid)
GROUP BY pv_users.age; --查询结果放到hdfs文件系统中
若是数据要存到多个不一样的分区:
multi-insert:
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='US')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'US'
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='CA')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'CA'
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='UK')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'UK';
这种方式,每次增长一个新的国家,都要修改代码增长一个insert分支语句,并且由于每个insert可能被看成一个Map/Reduce任务,效率低。
下面这种方式会根据数据内容自动将数据插入到对应分区中,若是分区不存在会自动建立,并且只有一个MR任务,效率高。
Dynamic-partition insert:
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country)
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.country
二者的不一样点:
country出如今partition中,可是不指定具体值,这代表country是一个动态分区列,dt指定了值,是一个静态分区列。若是一个列是动态分区列,那么它的值取自数据。动态分区列要放到partition子句的最后,如PARTITION(dt='2008-06-08',country),由于这个顺序代表了分区的层次,这个例子说明country是dt分区下面的子分区。
select子句中要把动态分区列指定为查询列。
总结:
同一分区下,若是数据相同,会覆盖分区数据,由于 OVERWRITE TABLE。
hive分区相似hdfs目录概念,因此分区名要规范,若有特殊字符会转换成%dd格式,若是不是string类型,会转换为string以后做为分区名,在hdfs上建立目录。
若是输入列是null或者空字符串,数据会放到一个特殊的分区中,由参数hive.exec.default.partition.name指定,默认值为HIVE_DEFAULT_PARTITION{}。
动态建立分区可能短期建立大量分区:
hive.exec.max.dynamic.partitions.pernode
默认100,一个mapreduce任务中最多能建立的分区数目
hive.exec.max.dynamic.partitions
默认1000,一个dml语句能建立的最大动态分区数目。
hive.exec.max.created.files
默认100000,全部的MR任务能够建立的文件总数
只指定动态分区列,未指定静态分区列:
hive.exec.dynamic.partition.mode=strict
该模式下,必需要指定一个静态分区列
hive.exec.dynamic.partition=true/false
启用或禁用动态分区列,默认false
数据保存到本地:
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/pv_gender_sum'
SELECT pv_gender_sum.*
FROM pv_gender_sum;
union all、array、map的操做,见官网。