点击上方 "大数据肌肉猿"关注, 星标一起成长
点击下方链接,进入高质量学习交流群
分享一位学习群同学的转型经历,他是二本土木类工程管理专业,17年毕业,毕业后在长沙工地从事了近5年,上半年开始学习大数据,前几个月拿了长沙和深圳多个大数据offer,后面选择了深圳一家甲方公司,目前已通过试用期,分享一些转型感受。
前言
我是普通二本的本科生,学的是工程管理专业。毕业时,工作半年左右开始仔细思考,到底想要以一个什么样的职业,融入我国发展大潮。彼时互联网风起云涌,此起彼伏互联网暴富的消息被各路媒体争相报导。
恰巧18年末在星球遇到了峰哥分享他的个人经历,于是加了他微信进了学习群,峰哥在群里分享了很多资料和经验,那时整个群基本都不是做大数据,但这几年很多人陆陆续续都转型成功了。
我最开始自学了一段时间,后来因为工作原因就停滞了,现在想想挺后悔的,要是早点转,目前薪资待遇可以更高。
今年年初因为疫情在家没法工作,在考虑了一段时间之后,就决心转大数据了。开始正式找峰哥帮忙规划学习路线和指导面试,学了几个月,年中开始面试。
最后拿到长沙一家大型制造业还有一家互联网公司,薪资在15-17w左右,拿了深圳两家外包18k,还有一家金融科技甲方19k的offer。
为什么转大数据
大数据是互联网发展的一定时期的产物。人口红利已经慢慢消失,逐渐从增量市场转向存量市场。存量市场没有增量市场那样好做,如何在现用的存量市场中更好的发展自己的企业呢?就精准营销了嘛。这就需要数据开发、数据分析、数据挖掘,产生用户画像、数据报表来为决策层决策、精准营销提供量化的依据。这正符合了“技术是演进出来的,不是想出来的”。
另外一个主要原因是工地干到头了,加上疫情原因经常停工,工作环境也比较压抑,一年干到头存不了几万块钱。
虽然今年互联网行情没有往年好,但我对比了一圈,发现还是远远比其他我能选择的行业好。
方法论
我认为先入行把技术学到手最重要,技术是程序员的核心竞争力,技术好了也就有了议价权。
在长沙
在进入一个新行业的时候,很需要有经验的过来人给到一些指导性的建议和学习方法,峰哥对我来说也就是这个过来人。
年初和峰哥详细聊了当时的个人情况,在峰哥帮我规划了学习路线和学习计划,然后就开始学了。
学的过程中,由于是接触新东西。比较吃力,心态偶尔也爆炸一下。这个时候找峰哥聊聊天。找个方式发泄一下,然后回来继续学就好了。
至于学习路线基本都是峰哥公众号分享的这些,非常赞同峰哥说的一句话:前期学习少即是多。所以前期学习并没有想象中的复杂,反而只需要学关键的一些知识点,有种四两拨千斤的感觉。
开始面试,有面试通知的话,针对jd突击学一下,面试中问面试官自己哪里不足,面试后总结。总结后继续面。面试后总结。总结后继续面。循环往复,期间和峰哥保持联系,峰哥会给到很 nice 的建议的。
就这样几个月在长沙面了几家就面试成功了,拿了两个offer,我也就去了。
公司挺大,一周五天班,朝九晚六不打卡。这就给到了我足够的时间查漏补缺,我也趁空余都在公司学习。一个月过去了,与同事交流,都感觉公司的项目没有想象中的复杂。慢慢开始意识到成长的速度似乎与一线脱节了。
干了一个多月我离职了,准备去一线工作。
在深圳
和一线的同学和前辈沟通了之后,当然也有峰哥哈。我8月份来了深圳。
然后开始投简历,面试总结调整,循环。找了将近1个月的工作,期间多次和峰哥交流面试相关的问题。刚开始拿了2个外包offer,后来又拿了金融甲方,然后就选择加入了,最近已经成功转正,感谢峰哥试用期的指导。
接下去的计划是继续精进自己的技术,在深圳多呆几年,后面回长沙选择也可以更多。
面试题摘要(整理了一些经常被问到的hive知识点)
一、sql 相关问题
怎么查看表结构,表创建语句?怎么查看表有哪些分区?怎么查看分区对应 hdfs 路径?
--查看表结构信息
--显示如何创建一个表
--怎么查看表有哪些分区
--hive怎么查看分区对应 hdfs 路径
怎么计算某个分区的数据量大小?怎么计算某个分区的文件总数?
有几种表连接(join)?
hive查询快速查找表大小(即行数)
如果表被分区
hive> analyze table ops_bc_log partition(day) compute statistics noscan; 输出是 分区logdata.ops_bc_log {day = 20140523} stats:[numfiles = 37,numrows = 26095186,totalsize = 654249957,rawdatasize = 58080809507] 分区logdata.ops_bc_log {day = 20140521} stats:[numfiles = 30,numrows = 21363807,totalsize = 564014889,rawdatasize = 47556570705] 分区logdata.ops_bc_log {day = 20140524} stats:[numfiles = 35,numrows = 25210367,totalsize = 631424507,rawdatasize = 56083164109] 分区logdata.ops_bc_log {day = 20140522} stats:[numfiles = 37,numrows = 26295075,totalsize = 657113440,rawdatasize = 58496087068]
一 hive sql ,怎么计算这个 sql 会产生多少个 map 数?
概念
1 map的数量
2 reduece的数量
hadoop在运行一个mapreduce job之前,需要估算这个job的maptask数和reducetask数。首先分析一下job的maptask数,当一个job提交时,jobclient首先分析job被拆分的split数量,然后吧job.split文件放置在hdfs中,一个job的maptask数量就等于split的个数。
job.split中包含split的个数由fileinputformat.getsplits计算出,方法的逻辑如下:
总结:
通过map和reducetask数量的分析可以看出,hadoop/hive估算的map和reduce task数可能和实际情况相差甚远。假定某个job的input数据量庞大,reduce task数量也会随之变大,而通过join和group by,实际output的数据可能不多,但reduce会输出大量的小文件,这个job的下游任务将会启动同样多的map来处理前面reduce产生的大量文件。在生产环境中每个user group有一个map task数的限额,一个job启动大量的map task很显然会造成其他job等待释放资源。
hive对于上面描述的情况有一种补救措施,参数hive.merge.smallfiles.avgsize控制hive对output小文件的合并,当hiveoutput的文件的平均大小小于hive.merge.smallfiles.avgsize-默认为16mb左右,hive启动一个附加的mapreducejob合并小文件,合并后文件大小不超过hive.merge.size.per.task-默认为256mb。
尽管hive可以启动小文件合并的过程,但会消耗掉额外的计算资源,控制单个reduce task的输出大小>64mb才是最好的解决办法。
map数据计算示例:
hive> set dfs.block.size; dfs.block.size=268435456 hive> set mapred.map.tasks; mapred.map.tasks=2 //文件块大小为256mb,map.tasks为2
查看文件大小和文件数:
[dwapp@dw-yuntigw-63 hadoop]$ hadoop dfs -ls /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25; 结果: found 18 items -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290700555 2012-11-26 19:00 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000000_0 -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290695945 2012-11-26 18:59 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000001_0 -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290182606 2012-11-26 19:00 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000002_0 ......
计算:
goalsize = 4539.059804 (文件总大小)/ mapred.map.tasks(2) = 2269.529902mb
因此splitsize取值为256mb,所以一共分配18个map。
若修改map.tasks参数为32
set mapred.map.tasks = 32;goalsize = 4539.059804 / mapred.map.tasks(32) = 141.8456189
因此splitsize取值为141.8mb,所以一共分配36个map。
sort by、distribute by、cluster by 和 order by 区别?
order by
对输入做全局排序,因此只有一个reducer。然而只有一个reducer,会导致当输入规模较大时,消耗较长的计算时间。
sort by
sort by的数据只能保证在同一个reduce中的数据可以按指定字段排序。使用sort by你可以指定执行的reduce个数(通过set mapred.reduce.tasks=n来指定),对输出的数据再执行归并排序,即可得到全部结果。
distribute by
distribute by是控制在map端如何拆分数据给reduce端的。sort by为每个reduce产生一个排序文件。在有些情况下,你需要控制某个特定行应该到哪个reducer,这通常是为了进行后续的聚集操作。distribute by刚好可以做这件事。因此,distribute by经常和sort by配合使用。hive要求distribute by要写在sort by之前。
cluster by
cluster by==distribute by+sort by。但是排序只能是倒叙排序,不能指定排序规则为asc或者desc。
注:distribute by和sort by的使用场景
**1.**map输出的文件大小不均。
**2.**reduce输出文件大小不均。
**3.**小文件过多。
**4.**文件超大。
hive (hive)> select * from temperature distribute by year sort by year asc,tempra desc;
a 表和 b 表内连接,a表为小表,只有2000 行记录,可以进行怎么样的优化?select a.* from a join b on a.key=b.key;
可以让hive自动识别,把join变成合适的map join如下所示
注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中
set hive.auto.convert.join=true; select a.* from a join b on a.key=b.key;
a表 left join b 表,b表为小表,可以进行怎么样的优化?select a.* from a left join b on a.key=b.key;
两大表连接,发生了数据倾斜,有几个 reduce 无法完成,怎么查找发生数据倾斜的原因?怎么优化?
每天图书馆的人流量信息被记录在这三列信息中:序号(id)、日期(date)、人流量(people)。请编写一个查询语句,找出高峰期时段,要求连续三天及以上,并且每天人流量均不少于100。
ps:每天只要一行记录,日期随 id 的增加而增加。
表table_1
id
date
people
1 | 2017-01-01 | 10 |
2 | 2017-01-02 | 109 |
3 | 2017-01-03 | 150 |
4 | 2017-01-04 | 99 |
5 | 2017-01-05 | 145 |
6 | 2017-01-06 | 1455 |
7 | 2017-01-07 | 199 |
8 | 2017-01-08 | 188 |
输出为
id
date
people
5 | 2017-01-05 | 145 |
6 | 2017-01-06 | 1455 |
7 | 2017-01-07 | 199 |
8 | 2017-01-08 | 188 |
答案:
如果只是找出全部人流量不少于100的记录不难,难点在于如何查找连续的三天,一个想法是,查 3 张表,让三个结果 id 连续
select a.*
from stadium as a,stadium as b,stadium as c
where (a.id = b.id-1 and b.id+1 = c.id)
and (a.people>=100 and b.people>=100 and c.people>=100);
但是这样输出会有问题,比如 5,6,7,8 号人流量不少于100,但是只输出了 5,6号,根本原因在于,我们将 a 的 id 设为三个连续值中最小值,所以只返回了每 3 个连续值中最小的一个,同理可想到,我们再将 a 的 id 设为三个连续值中中间值和最大值,可以得到全部的连续 3 个值
select a.*
from stadium as a,stadium as b,stadium as c
where ((a.id = b.id-1 and b.id+1 = c.id) or
(a.id-1 = b.id and a.id+1 = c.id) or
(a.id-1 = c.id and c.id-1 = b.id))
and (a.people>=100 and b.people>=100 and c.people>=100);
但是这样还有个问题,比如 5,6,7,8,6 既是 5,6,7 的中间值也是 6,7,8 的最小值,所以还要去重,也许 id 不按序排列,再排序 id,最终得到答案
select distinct a.*
from stadium as a,stadium as b,stadium as c
where ((a.id = b.id-1 and b.id+1 = c.id) or
(a.id-1 = b.id and a.id+1 = c.id) or
(a.id-1 = c.id and c.id-1 = b.id))
and (a.people>=100 and b.people>=100 and c.people>=100)
order by a.id;
链接:https://leetcode-cn.com/problems/human-traffic-of-stadium/solution/ti-yu-guan-de-ren-liu-liang-by-little_bird/
来源:力扣(leetcode)
二、join 优化
实际生产环境中,一天的数据可能有50g
mapjoin(大表对小表)
设置:
可以让hive自动识别,把join变成合适的map join如下所示
注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中
set hive.auto.convert.join=true;
select /*+ mapjoin(time_dim) */ count(*) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)
大表对大表,既然是两个表进行join,肯定有相同的字段吧。
set hive.auto.convert.sortmerge.join=true
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;
bucket map join
map join 效率比 common join 效率好,但总会有“小表”条件不满足的时候。这就需要 bucket map join 了。
bucket map join 需要待连接的两个表在连接字段上进行分桶(每个分桶对应hdfs上的一个文件),而且小表的桶数需要时大表桶数的倍数。
建立分桶表的例子:
create table my_user
(uid int,
name string)
clustered by (uid) into 32 buckets
stored as textfile;
这样,my_user 表就对应 32 个桶,数据根据 uid 的 hash value 与32 取余,然后被分发导不同的桶中。
如果两个表在连接字段上分桶,则可以执行 bucket map join 了,具体的:
设置属性 hive.optimize.bucketmapjoin= true 控制 hive 执行 bucket map join;
对小表的每个分桶文件建立一个 hashtable,并分发到所有做连接的 map端;
map 端接受了n(n为小表分桶的个数) 个小表的 hashtable,做连接操作的时候,只需要将小表的一个 hashtable 放入内存即可,然后将大表的对应的 split 拿出来进行连接,所以其内存限制为小表中最大的那个hashtable 的大小。
sort merge bucket map join
对于 bucket map join 中的两个表,如果每个桶内分区字段也是有序的,则还可以进行 sort merge bucket map join。
建表语句为:
create table my_user
( uid int,
name string)
clustered by (uid) sorted by (uid) into 32 buckets
stored as textfile;
这样一来当两边 bucket 要做局部 join 的时候,只需要用类似 merge sort 算法中的 merge 操作一样把两个 bucket 顺序遍历一遍即可完成,小表的数据可以每次只读取一部分,然后还是用大表一行一行的去匹配,这样的join 没有限制内存的大小. 并且也可以执行全外连接。
进行sort merge bucket map join时,需要设置的属性为:
set hive.optimize.bucketmapjoin= true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format = org.apache.hadoop.hive.ql.io.bucketizedhiveinputformat;
join 的对比
join类型
优点
缺点
common join | 可以完成各种 join 操作,不受表大小和表格式的限制 | 无法只在 map 端完成 join 操作,耗时长,占用更多地网络资源 |
map join | 可以在 map 端完成 join 操作,执行时间短 | 待连接的两个表必须有一个“小表”,“小表”必须加载内存中 |
bucket map join | 可以完成 map join,不受“小表”限制 | 表必须分桶,做连接时小表分桶对应 hashtable 需要加载到内存 |
sort merge bucket map join | 执行时间短,可以做全连接,几乎不受内存限制 | 表必须分桶,而且桶内数据有序 |
三、数据倾斜处理
数据倾斜可能会发生在group过程和join过程。
大表和小表关联
多表关联时,将小表(关联键重复记录少的表)依次放到前面,这样可以触发 reduce 端更少的操作次数,减少运行时间。
同时可以使用 map join 让小的维度表缓存到内存。在map端完成join过程,从而省略掉redcue端的工作。但是使用这个功能,需要开启map-side join的设置属性:set hive.auto.convert.join=true(默认是false)
同时还可以设置使用这个优化的小表的大小:set hive.mapjoin.smalltable.filesize=25000000(默认值25m)
————————————————
原文链接:https://blog.csdn.net/qq_26442553/article/details/80866723
大表和大表的关联
大表与大表关联,如果其中一张表的多是空值或者 0 比较多,容易 shuffle 给一个reduce,造成运行慢。
这种情况可以对异常值赋一个随机值来分散 key,均匀分配给多个 reduce 去执行,比如:
select *
from log a
left outer join users b
on case when a.user_id is null then concat('hive',rand() ) else a.user_id end = b.user_id;
-- 将a表垃圾数据(为null)赋一个随机的负数,然后将这些数据shuffle到不同reduce处理。
当 key 值都是有效值时,解决办法为:
设置以下参数:
# 每个节点的 reduce 默认是处理 1g 大小的数据
set hive.exec.reducers.bytes.per.reducer = 1000000000
# 如果 join 操作也产生了数据倾斜,可以设定
set hive.optimize.skewjoin = true;
set hive.skewjoin.key = skew_key_threshold (default = 100000)
hive 在运行的时候无法判断哪个 key 会产生倾斜,所以使用 hive.skewjoin.key 参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的 reduce,一般可以设置成待处理的总记录数/reduce 个数的 2-4 倍。
其他情况数据倾斜的处理
解决方式1:
hive.map.aggr=true (默认true) 这个配置项代表是否在map端进行聚合,相当于combiner
hive.groupby.skewindata=true(默认false)
似乎是解决数据倾斜的万能钥匙,查询计划会有两个 mr job,第一个 mr job 中,map 的输出结果集合会随机分布到 reduce 中,每个reduce做部分聚合操作,并输出结果,这样处理的结果是相同的 group by key 有可能被分发到不同的 reduce中,从而达到负载均衡的目的;第二个 mr job 再根据预处理的数据结果按照 group by key 分布到 reduce中(这个过程可以保证相同的 group by key 被分布到同一个 reduce 中),最后完成最终的聚合操作。
通用的一些数据倾斜的处理方法
1.reduce个数太少
reduce数太少set mapred.reduce.tasks=800;
默认是先设置hive.exec.reducers.bytes.per.reducer这个参数,设置了后hive会自动计算reduce的个数,因此两个参数一般不同时使用
2.当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;
--end--
扫描下方二维码
添加好友,备注【交流】
可围观朋友圈,也可私信交流
发表评论