面试介绍
应该是近期最后一场面试了. 面试官人很好, 就是约面试太慢了. 我12.09投的简历, 12.17才开始的一面, 12.22才开始的二面. 相比之下网易传媒就快很多, 12.09投的简历, 12.11一面, 12.14二面. 以至于我答应下来了offer这边的面试还没开始.
面试内容
首先还是按套路出牌, 自我介绍. 介绍完了之后面试官问大数据开发有很多领域, 对哪些感兴趣, 我回答的是偏业务的开发, 而不是数据仓库的开发和运维.
- 问的第一个就是如何用mapreduce实现下面的问题
1 | 假如有很大的数据, 比如4TB, 数据中每一行有多个列. 现在要求出对于指定的第i列, 求出所有行的第i列的数据之和 |
我一开始的解答就是把每一行的第i列的元素作为value, 给定一个常数1作为key, 进行reduce操作. 并且使用combiner. 我的理解是使用combiner就可以避免map端生成过多的key. 因为key只有1个, 所以在各个阶段进行combine之后传递给reducer的key就变得很少了. 因为在溢写的时候和归并排序的时候都会进行combiner.
面试官仍然问了把所有的数据集中在一个节点上会不会造成数据倾斜的问题, 我觉得除非是因为map任务太多, 要不然应该不会数据倾斜的. 不然根据默认的配置, 溢写文件大于3个就会在归并的时候再次进行combine操作. 所以每个map端最多生成3个文件传递给reducer.
然后还说了下spark中的解决方法就是用累加器.
- 第二个问题, 对垃圾回收的理解.
我当时听到垃圾回收这四个字, 心里就凉了. 因为我jvm还没学. (确实是我太不应该了, 既然给面试官说以后选java方向, 但是连jvm都不会也太说不过去了, 等这学期期末忙完就开始学jvm). 然后就说了些大概的, 不系统的知识吧, 因为之前学C++的时候学过智能指针, 知道引用计数的实现方式和优缺点. 所以就说了些引用计数, 对象头, 弱引用什么的. 可能说的有些地方也不太对.
- 然后就又到了写SQL的时候了, 给定一个表log, 里面记录了用户id, 用户触发某个事件的id, 及触发这个事件的时间.
要统计每一天中新用户的数量. (新用户就是指uid第一次出现, 之前的记录中uid没有出现过的用户)
1 | # timestamp uid eventid |
我的想法是左连接*(其实这题我知道用窗口函数更简单, 但我忘了选择某个列的前一个记录对应的窗口函数名是什么了, 所以没敢说)**, 连接的条件就是左表的id等于右表的id, 并且左表的时间大于右表的时间. 这样, 如果左表中的某一列是该id第一个记录的话, 那么不存在某一条右表记录, 使得左表的时间大于右表的时间. 即右表的部分为NULL. 我们按天来统计NULL的个数就能发现当天新用户的数量了. 也解释了下count()是会统计NULL的行的数量, 而count(date2)不会, 所以相减就可以得到NULL行的个数了
然后面试官说这样的逻辑对, 但是有没有什么问题. 那肯定是性能有问题, 我说了一下连接操作, count操作, group by操作都需要遍历.非常耗时间. (然后还有的问题就说连接产生的临时表会非常大, 因为左表的一行可能被右表连接了好几次, 这点我面试的时候没意识到, 面完才想到).
又问解决的方法, 我给出了两种, 第一种就是再添一列, 记录相同id的上一行记录. 如果没有上一行记录, 就说明当前是一个新用户. 类似于链表指针. 第二种方法就是用窗口函数. 我也只是知道窗口函数能做这个问题, 至于怎么写就不会了, 也幸亏面试官没让我写.
然后接下来就没问什么专业性的问题了, 就是聊天了, 面试官介绍了大数据开发的几个方向吧, 然后问问我喜欢什么, 我也问了面试官组里主要是负责有道的什么部分. 感觉不太是我想要去的岗位. 而且已经接受了另外的offer了, 最后在微信上就婉拒了. 不得不说有道的面试都是这样的吗? 要面试官提前联系面试者, hr什么都不管?