行转列:explode
列转行:
使用函数:concat_ws(',',collect_set(column))
说明:collect_list 不去重,collect_set 去重。 column的数据类型要求是stringhive 基础知识的总结回顾 内含我收集的几个sql题目, 用来回顾练手的
包括一些优化相关的总结
建表语法 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path]
说明: 1、CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。 2、EXTERNAL关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。 3、LIKE 允许用户复制现有的表结构,但是不复制数据。 4、ROW FORMAT DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char] [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char] | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)] 用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive通过 SerDe 确定表的具体的列的数据。 5、STORED AS SEQUENCEFILE|TEXTFILE|RCFILE 如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
6、CLUSTERED BY 对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
2.2.1Load 语法结构 LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
说明: 1、Load 操作只是单纯的复制/移动操作,将数据文件移动到 Hive 表对应的位置。 2、filepath: 相对路径,例如:project/data1 绝对路径,例如:/user/hive/project/data1 包含模式的完整 URI,列如: hdfs://namenode:9000/user/hive/project/data1 3、LOCAL关键字 如果指定了 LOCAL, load 命令会去查找本地文件系统中的 filepath。 如果没有指定 LOCAL 关键字,则根据inpath中的uri[如果指定了 LOCAL,那么: load 命令会去查找本地文件系统中的 filepath。如果发现是相对路径,则路径会被解释为相对于当前用户的当前路径。 load 命令会将 filepath中的文件复制到目标文件系统中。目标文件系统由表的位置属性决定。被复制的数据文件移动到表的数据对应的位置。
如果没有指定 LOCAL 关键字,如果 filepath 指向的是一个完整的 URI,hive 会直接使用这个 URI。 否则:如果没有指定 schema 或者 authority,Hive 会使用在 hadoop 配置文件中定义的 schema 和 authority,fs.default.name 指定了 Namenode 的 URI。 如果路径不是绝对的,Hive 相对于/user/进行解释。 Hive 会将 filepath 中指定的文件内容移动到 table (或者 partition)所指定的路径中。]查找文件
4、OVERWRITE 关键字 如果使用了 OVERWRITE 关键字,则目标表(或者分区)中的内容会被删除,然后再将 filepath 指向的文件/目录中的内容添加到表/分区中。 如果目标表(分区)已经有一个文件,并且文件名和 filepath 中的文件名冲突,那么现有的文件会被新文件所替代。
- 没有local的话 就是在hdfs中, 会将其移动过去
将查询结果插入Hive表 语法结构 利用查询语句,将查询结果插入新的表 INSERT OVERWRITE [INTO] TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement
插入一条数据 INSERT INTO TABLE VALUES(XX,YY,ZZ);
Multi Inserts多重插入: FROM from_statement INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select statement1 [INSERT OVERWRITE TABLE tablename2 [PARTITION ...] Select statement2] ...
Dynamic partition inserts动态分区插入: INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement
- 可以动态分区插入
- partition里面是 select里面的列
- gzip压缩
- 压缩率比较高,而且压缩/解压速度也比较快
- 缺点:不支持split
- 应用场景
- 当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用gzip压缩格式
- lzo压缩
- 优点
- 压缩/解压速度也比较快,合理的压缩率
- 支持split,是hadoop中最流行的压缩格式
- 压缩率比gzip要低一些;hadoop本身不支持,需要安装
- 应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越越明显
- snappy
- 优点:高速压缩速度和合理的压缩率;支持hadoop native库。
- 缺点:不支持split;压缩率比gzip要低
- 应用场景
- 当mapreduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式
- 或者作为一个mapreduce作业的输出和另外一个mapreduce作业的输入。
- bzip2
- 优点
- 支持split
- 具有很高的压缩率,比gzip压缩率都高
- 缺点:压缩/解压速度慢;不支持native。
- 应用场景
- 适合对速度要求不高,但需要较高的压缩率的时候
- 可以作为mapreduce作业的输出格式
- 或者输出之后的数据比较大,处理之后的数据 需要压缩存档减少磁盘空间并且以后数据用得比较少的情况
- 或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程 序(即应用程序不需要修改)的情况
- ORC是在一定程度上扩展了RCFile,是对RCFile的优化
- orc.compress ZLIB high level compression (one of NONE, ZLIB, SNAPPY)
- 结构
- ORCFile在RCFile基础上引申出来Stripe和Footer
- 每个ORC文件首先会被横向切分成多个Stripe,而每个Stripe内部以列存储
- IndexData中保存了该stripe上数据的位置信息,总行数等信息
- RowData以stream的形式保存了数据的具体信息
- Stripe Footer中包含该stripe的统计结果,包括Max,Min,count等信息
- Hive读取数据的时候,根据FileFooter读出Stripe的信息,根据IndexData读出数据的偏移量从而读取出数据
- 压缩
- ZLIB
- 支持的引擎
- hive
- parquet
- Parquet文件是以二进制方式存储的,是不可以直接读取和修改的
- Parquet文件是自解析的,文件中包括该文件的数据和元数据
- 压缩
- snappy
- gzip
- 支持的引擎
- drill
- impala
- hive
- avro
- CREATE TABLE kst
PARTITIONED BY (ds string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
TBLPROPERTIES (
'avro.schema.url'='http://schema_provider/kst.avsc')
利用reduce排序的特性
sum(pv) over (partition by cookieid order by createtime rows between unbounded preceding and current row) as pv1, sum(pv) over (partition by cookieid order by createtime) as pv2, sum(pv) over (partition by cookieid) as pv3, sum(pv) over (partition by cookieid order by createtime rows between 3 preceding and current row) as pv4, sum(pv) over (partition by cookieid order by createtime rows between 3 preceding and 1 following) as pv5, sum(pv) over (partition by cookieid order by createtime rows between current row and unbounded following) as pv6
如果不指定ROWS BETWEEN,默认为从起点到当前行; 如果不指定ORDER BY,则将分组内所有值累加; 关键是理解ROWS BETWEEN含义,也叫做WINDOW子句: PRECEDING:往前 FOLLOWING:往后 CURRENT ROW:当前行 UNBOUNDED:起点,
GROUPING__ID,表示结果属于哪一个分组集合
先水平划分,再垂直划分的理念
首先将表分为几个行组,对每个行组内的数据进行按列存储,每一列的数据都是分开存储
行转列:explode
列转行:
使用函数:concat_ws(',',collect_set(column))
说明:collect_list 不去重,collect_set 去重。 column的数据类型要求是string
我使用Hive对数据做一些类型统计的时候遇到过某种类型的数据量特别多,而其他类型数据的数据量特别少。当按照类型进行group by的时候,会将相同的group by字段的reduce任务需要的数据拉取到同一个节点进行聚合,而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这里还没计算完成,其他节点的一直等待这个节点的任务执行完成,所以会看到一直map 100% reduce 99%的情况。
解决方法:set hive.map.aggr=true set hive.groupby.skewindata=true set hive.groupby.mapaggr.checkintenval=1000000; 这个是group的键对应的记录条数超过这个值则会进行优化 原理:hive.map.aggr=true 这个配置项代表是否在map端进行聚合 hive.groupby.skwindata=true 当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
1.当出现小文件过多,需要合并小文件。可以通过set hive.merge.mapfiles=true来解决。 2.单个文件大小稍稍大于配置的block块的大写,此时需要适当增加map的个数。解决方法:set mapred.map.tasks个数 3.文件大小适中,但map端计算量非常大,如select id,count(*),sum(case when...),sum(case when...)...需要增加map个数。解决方法:set mapred.map.tasks个数,set mapred.reduce.tasks个数
当HiveQL中包含count(distinct)时, 如果数据量非常大,执行如select a,count(distinct b) from t group by a;类型的SQL时,会出现数据倾斜的问题。 解决方法:使用sum...group by代替。如select a,sum(1) from (select a, b from t group by a,b) group by a;
解决方法:使用mapjoin 将小表加载到内存中。 当表小于25mb的时候,小表自动注入内存 set hive.auto.convert.join=true; set hive.mapjoin.smalltable.filesize=25mb; 默认值是25mb
两阶段处理 set hive.optimize.skewjoin=true;如果是join过程出现倾斜 应该设置为true set hive.skewjoin.key=1000000;--这个是join的键对应的记录条数超过这个值则会进行优化
cluster by:对同一字段分桶并排序,不能和 sort by 连用 distribute by + sort by:分桶,保证同一字段值只存在一个结果文件当中,结合 sort by 保证 每个 reduceTask 结果有序 sort by:单机排序,单个 reduce 结果有序 order by:全局排序,缺陷是只能使用一个 reduce
小文件合并 文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的 结果文件来消除这样的影响:
set hive.merge.mapfiles = true ##在 map only 的任务结束时合并小文件
set hive.merge.mapredfiles = false ## true 时在 MapReduce 的任务结束时合并小文件
set hive.merge.size.per.task = 25610001000 ##合并文件的大小
set mapred.max.split.size=256000000; ##每个 Map 最大分割大小
set mapred.min.split.size.per.node=1; ##一个节点上 split 的最少值
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; ##执行 Map 前进行小文件合并
这几个面试题是手生的时候的,用来回顾的题目 https://www.cnblogs.com/qingyunzong/p/8747656.html
现要求出:每个用户截止到每月为止的最大单月访问次数和累计到该月的总访问次数 用户名uname,月份umonth,访问次数ucount A,2015-01,5 A,2015-01,15 B,2015-01,5 A,2015-01,8 B,2015-01,25 A,2015-01,5 A,2015-02,4 A,2015-02,6 B,2015-02,10 B,2015-02,5 A,2015-03,16 A,2015-03,22 B,2015-03,23 B,2015-03,10 B,2015-03,1
create external table if not exists t_access( uname string comment '用户名', umonth string comment '月份', ucount int comment '访问次数' ) comment '用户访问表' row format delimited fields terminated by ","
结果数据格式如下
select uname, umonth, count(*) from table group by uname, umonth
select uname, umonth sum(ucount) over(partition by uname order by uname, umonth rows between unbounded preceding and current row)
select uname, umonth max(ucount) over(partition by uname order by uname, umonth rows between unbounded preceding and current row)
select
uname,umonth ,
max(sum_count) over(ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), total_count,sum_count #
from
(select uname,umonth ,max(total_sum) as total_count ,sum(ucount) as sum_count #求出当前用户,当前月的访问次数
from
(select uname,umonth,ucount,
sum(ucount) over(partition by uname order by uname,umonth #最内层求出累计到本月的总访问次数
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
as total_sum
from t1
) as tmp1
group by uname,umonth
) as tmp2 order by uname,umonth;
用sql求出所有数学课程成绩 大于 语文课程成绩的学生的学号
CREATE TABLE `course` (
`id` int,
`sid` int ,
`course` string,
`score` int
) ;
// 字段解释:id, 学号, 课程, 成绩
INSERT INTO `course` VALUES (1, 1, 'yuwen', 43);
INSERT INTO `course` VALUES (2, 1, 'shuxue', 55);
INSERT INTO `course` VALUES (3, 2, 'yuwen', 77);
INSERT INTO `course` VALUES (4, 2, 'shuxue', 88);
INSERT INTO `course` VALUES (5, 3, 'yuwen', 98);
INSERT INTO `course` VALUES (6, 3, 'shuxue', 65);
select a.sid
from course a join course b on a.sid = b.sid and a.course = 'shuxue' and b.course ='yuwen'
where a.score > b.score;
create view tmp_course_view as
select sid, case course when "shuxue" then score else 0 end as shuxue,
case course when "yuwen" then score else 0 end as yuwen from course;
create view tmp_course_view1 as
select aa.sid, max(aa.shuxue) as shuxue, max(aa.yuwen) as yuwen from tmp_course_view aa group by sid;
select * from tmp_course_view1 where shuxue > yuwen;
求出id为1,2,3的学生选修了课程a,b,c,d,e,f中其中几门。
create table t_course(id int,course string) row format delimited fields terminated by ",";
id course 1,a 1,b 1,c 1,e 2,a 2,c 2,d 2,f 3,a 3,b 3,c 3,e
select id,
if(find_in_set('a',courses)==0,0,1) as a,
if(find_in_set('b',courses)==0,0,1) as b,
if(find_in_set('c',courses)==0,0,1) as c,
if(find_in_set('d',courses)==0,0,1) as d,
if(find_in_set('e',courses)==0,0,1) as e
from
(
select id,concat_ws(',',collect_list(cid)) as courses
from t3
group by id) tmp;