一.数据倾斜
在计算数据的时候,数据的分散度不够,导致大量的数据集中到了一台或者几台机器上计算,这些数据的计算速度远远低于平均计算速度,导致整个计算过程过慢。
如何解决
订单场景,某一天在北京和上海两个城市多了强力的推广,结果可能是这两个城市的订单量增长了10000%,其余城市的数据量不变。然后我们要统计不同城市的订单情况,这样,一做group操作,可能直接就数据倾斜了。
解决数据倾斜有这几个思路:
1.业务逻辑,上面的例子,我们单独对这两个城市来做count,最后和其它城市做整合。
2.程序层面,Hive中,经常遇到count(distinct)操作,这样会导致最终只有一个reduce,可以先group 再在外面包一层count。
3.调参方面,Hadoop和Spark都自带了很多的参数和机制来调节数据倾斜,合理利用它们就能解决大部分问题。
set hive.exec.reducers.max=200;
set mapred.reduce.tasks= 200;---增大Reduce个数
set hive.groupby.mapaggr.checkinterval=100000 ;--group的键对应的记录条数超过这个值则会进行分拆,值根据具体数据量设置
set hive.groupby.skewindata=true; --如果是group by过程出现倾斜 应该设置为true
set hive.skewjoin.key=100000; --这个是join的键对应的记录条数超过这个值则会进行分拆,值根据具体数据量设置
set hive.optimize.skewjoin=true;--如果是join 过程出现倾斜 应该设置为true
从业务和数据上解决数据倾斜 :
有损的方法:
找到异常数据,比如ip为0的数据,过滤掉
无损的方法:
对分布不均匀的数据,单独计算
先对key做一层hash,先将数据打散让它的并行度变大,再汇集
数据预处理
二.常用函数
1.FIRST_VALUE
取分组内排序后,截止到当前行,第一个值
2.LAST_VALUE
取分组内排序后,截止到当前行,最后一个值
用法:
first_value(testtype) over (partition by device_id order by create_time desc) as testtype
3.lateral view explode
lateral view用于和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分 成一行或者多行,lateral view在把结果组合,产生一个支持别名表的虚拟表。
A B C
190 [1030,1031,1032,1033,1190] select id
191 [1030,1031,1032,1033,1190] select id
希望的结果是:
190 1030 select id
190 1031 select id
190 1032 select id
190 1033 select id
190 1190 select id
191 1030 select id
191 1031 select id
191 1032 select id
191 1033 select id
191 1190 select id
select A,B,C from table_1 LATERAL VIEW explode(B) table1 as B得到上述结果
4.字符串连接函数:concat
语法: concat(string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,支持任意个输入字符串
举例:
hive> select concat(‘abc’,'def’,'gh’) from lxw_dual;
abcdefgh
5.带分隔符字符串连接函数:concat_ws
语法: concat_ws(string SEP, string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,SEP表示各个字符串间的分隔符
举例:
hive> select concat_ws(‘,’,'abc’,'def’,'gh’) from dual;
abc,def,gh
6.collect_max
语法:FUNC(x,val,n)其中n是要返回的值的数量,val为double类型。
说明:Similar to collect, but save only the keys containing the max 20 values.
举例 :collect_max(coalesce(receiver_mobile, ''), cast(mobile_cnt as double), 3)
返回三个 map
7.map_keys
语法:map_keys(Map)
返回值:Returns an unordered array containing the keys of the input map.
说明:
举例:map_keys(collect_max(coalesce(receiver_mobile, ''), cast(mobile_cnt as double), 3))
8.map_values
语法:map_values(Map)
返回值:Returns an unordered array containing the values of the input map.
说明:
9.unix_timestamp
获取当前UNIX时间戳函数: unix_timestamp
语法: unix_timestamp()
返回值: bigint
说明: 获得当前时区的UNIX时间戳
举例:
hive> select unix_timestamp() from dual;
1323309615
日期转UNIX时间戳函数: unix_timestamp
语法: unix_timestamp(string date)
返回值: bigint
说明: 转换格式为“yyyy-MM-dd HH:mm:ss“的日期到UNIX时间戳。如果转化失败,则返回0。
举例:
hive> select unix_timestamp(’2011-12-07 13:01:03′) from dual;
1323234063
指定格式日期转UNIX时间戳函数: unix_timestamp
语法: unix_timestamp(string date, string pattern)
返回值: bigint
说明: 转换pattern格式的日期到UNIX时间戳。如果转化失败,则返回0。
举例:
hive> select unix_timestamp(’20111207 13:01:03′,’yyyyMMdd HH:mm:ss’) from dual;
1323234063
9.lag,lead
lag 和lead 可以 获取结果集中,按一定排序所排列的当前行的上下相邻若干offset 的某个行的某个列(不用结果集的自关联);lag ,lead 分别是向前,向后
语法:LAG(col,n,DEFAULT)
说明:用于统计窗口内往上第n行值,第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)
返回值:见说明
举例:
HIve> select * from kkk;
ID NAME
---------- --------------------
1 1name
2 2name
3 3name
4 4name
5 5name
HIve> select id,name,lag(name,1,0) over ( order by id ) from kkk;
ID NAME LAG(NAME,1,0)OVER(ORDERBYID)
---------- -------------------- ----------------------------
1 1name 0
2 2name 1name
3 3name 2name
4 4name 3name
5 5name 4name
HIve> select id,name,lead(name,2,0) over ( order by id ) from kkk;
ID NAME LEAD(NAME,2,0)OVER(ORDERBYID)
---------- -------------------- -----------------------------
1 1name 3name
2 2name 4name
3 3name 5name
4 4name 0
5 5name 0
10.GROUPING SETS
GROUPING SETS会把在单个GROUP BY逻辑中没有参与GROUP BY的那一列置为NULL值,使它成为常量占位列。这样聚合出来的结果,未被GROUP BY的列将显示为NULL。但是数据表中很可能原来存在NULL值,所以会有歧义,为了解决这个歧义问题,可以使用HQL提供的一个Grouping__ID函数,这个函数没有参数,在有GROUPING SETS子句的情况下,把它直接放在SELECT子句中,独占一列。它返回的结果是一个看起来像整形数值类型,其实是字符串的值,这个值使用了位图策略(bitvector,位向量),即它的二进制形式中的每1位标示着对应列是否参与GROUP BY,如果某一列参与了GROUP BY,对应位就被置为1,否则为0,根据这个位向量值和对应列是否显示为NULL,就可以解决上面提到的歧义问题了。
11.get_json_object(string json_string, string path)
语法:get_json_object(ctx,'$.category_name') p.s加$.符号
返回值: string
说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。
类比:
parse_url(‘http://facebook.com/path/p1.php?query=1‘, ‘HOST’)返回’facebook.com’ ,
parse_url(‘http://facebook.com/path/p1.php?query=1‘, ‘PATH’)返回’/path/p1.php’ ,
parse_url(‘http://facebook.com/path/p1.php?query=1‘, ‘QUERY’)返回’query=1’,
12.日期增加函数 date_add(start_date, num_days)
返回类型:string
描述:返回增加num_days 天数的日期(负数则为减少)
date_add(start_date, num_days) - Returns the date that is num_days after start_date.
举例:
hive>select date_add('2014-09-16 15:50:08.119',10) from default.dual;
2014-09-26
hive>select date_add('2014-09-16 15:50:08.119',-10) from default.dual;
2014-09-06
13.日期减少函数 date_sub(start_date, num_days)
返回类型:string
描述:返回num_days 天数之前的日期(负数则为增加)
date_sub(start_date, num_days) - Returns the date that is num_days before start_date.
举例:
hive>select date_sub('2014-09-16 15:50:08.119',10) from default.dual;
2014-09-06
hive>select date_sub('2014-09-16 15:50:08.119',-10) from default.dual;
2014-09-26
三.查询优化
1.join前把不必要的数据滤掉,on字句不要加多余的判断(尽量尽早的过滤数据,减少每个阶段的数据量)
(tb13.test_device_id=tb3.imei and tb3.device_id!='')
2.对于连续的数值,能用 between 就不要用 in
select id from t where num in(1,2,3)
select id from t where num between 1 and 3
3.jion操作
小表要注意放在join的左边
否则会引起磁盘和内存的大量消耗
4.not in
select a.key from a left outer join b on a.key=b.key where b.key is null
5. 使用相同的连接键
当对3个或者更多个表进行join连接时,如果每个on子句都使用相同的连接键的话,那么只会产生一个MapReduce job。