MayCoder

Valarmorghulis

北美求职准备

近期离开了毕业后第一家公司,去 google zurich 工作了,还没来得及总结。有朋友想了解北美求职相关的事情,故写一点小心得仅供参考。 这里主要从在职人士的角度出发,也主要把我看过的资料,用过的服务提供给大家参考。最后附了一些资源,写的都很棒,看过一遍就会对整个北美求职有点感觉了。

基本信息

首先一般来说北美公司的面试时间窗口一般在下半年,从7,8月份开始一直可以延续到次年的二月份,大部分人会选择在这中间,比如九十月份来投简历面试。
在这之前要准备什么呢?

  • 一份英文简历
  • 英语听说能力
  • 专业技能

一般来说大部分人不管准备了多久都会觉得没有准备好,不过到时间了还是得申请面试的。面试最好找朋友内推,网申得到面试机会的概率略小。 内推完一般来说一两个星期就可以安排面试了,走各自的面试流程即可。在准备过程中,一个人准备往往会有局限,找到组织往往会加速成长。在13年中旬开始我留意到一个 北美求职组织 ,在其中认识了,连城,cy,方勤等同学, 从他们身上学到了很多东西。参加这样的小组织让你不是孤军奋战,每周的线下交流让你能够在互相讨论学习中收获到新的知识,成长更快。

简历

简历本该养成定期更新的良好习惯,这样就不用纠结了,可以参考我的 持续更新简历

英语

英语方面要求并不算高,一般做到能基本听懂,并能做出简单交流即可。面试一般都是专业词汇,稍微看点英文技术视频就会有点感觉了。更多的时候不会挂在英语上, 而是挂在专业知识上。之前我的英文准备也没有很规范,大概有以下两项:

  • 51talk
    这个最有趣,当时想着要提高口语, 得找一个"外国人"1对1演练一下。在网上找了,相中了 51tak 这个"外教" 1对1服务。 51talk的外教多半是东南亚赚外快的英语老师,当时办60次的月卡,一节课25块,一次25分钟, 一位 “外教” 使用 skype 或 QQ 进行 1 对 1 的英语训练。这个网站是瞄准了广大平民百姓的口语训练需求, 提供了物美价廉的服务。 在13年八月以来,我调整了工作日的起床时间,每天多安排了一节课,每周安排两三次,固定一位靠谱的老师。 长期下来感觉良好(虽然口语还是被老师批长句不行, 词汇不够)。如果有想要购买他家服务的同学可以找我沟通,我还有 120 节课没有用完。。。
  • friends
    一个快速提高英语的方法就是看英语电影或连续剧, 这里老友记确实很不错, 既休闲又能培养听力。身边有不止一个小伙伴说看了不下一遍的。

专业技能

专业技能方面我的准备也是略仓促,导致了在一些公司的求职失利。认真去准备一般即可有收获。大部分公司都考算法和数据结构,并且在几乎所有北美公司这部分都占了很大的比重。
简单粗暴的说法比如,经常会有拿offer的同学说,"leetcode 刷两三遍就够了,常见题目也就都看过了。" 确实是这样。

  • leetcode
    leetcode上的题目实在太经典了,做法多样,确实可以刷上两三遍。那么刷两三遍要达到什么目的呢? 给你一道leetcode的原题你能够短时间一次性完成, 尽量少犯错误,一步到最优做法,以及明白各种扩展。 github 上有很多人share leetcode 的切题记录可以参考, 官方论坛的讨论也都很不错。之前看到 一个比较老的对leetcode 的题目的难度以及面试出现频率做了统计的表格 可以参考一下,有侧重的刷题。

除了 leetcode, 有一份 mitbbs 整理的 面经题目综合文档 也不错,很有参考价值,类似 “历届真题” 的感觉。这里不仅有纯算法题,还有一些逻辑,概率,设计题。 考察实际工程实践抽象出的设计问题,这往往是比能够通过机械训练达到熟练的算法问题来的更难的更有区分度的。这方面我的积累深度还不够,也吃过亏。这部分感觉还得看个人工作中的总结与归纳,就不展开了。

Resource

意外的好运

昨天 笑来老师 来鄙厂做分享来着, 讲的挺好的, 趁着记忆还热乎赶紧发出来。 很早以前就通过把时间做朋友认识笑来老师了(惭愧的是这本书还没有看完), 去年又看到他自学 rail 搞了一个还不错的创业产品 knewone, 感慨跨界神人也,今天在跟别人闲聊的时候才知道他是比特币大咖,四大天王之首, 顿觉此人太神了。盲目的崇拜是不好的,不过汲取一些成功的经验是有益的。

以下简写笑来老师为 xl。

Serendipity

开场提到了一个有趣的单词,Serendipity, 中文即是意外的好运,据说这个单词曾被翻译公司认定为十大最难翻译的词之一。
可以认为本次的分享通篇都围绕着意外的好运这个主题,通过各种真实案例来推导一个主题:

意外的好运可以创造。

把时间当朋友

有人提到为啥在新东方教学之后会写把时间当朋友这本书,xl解释到这是他在新东方教书的经验之谈,并且总结后发现这不仅仅是在学英语这件事上,这是一种 凶悍 学习方法论,也是他多年来坚持的学习方法。 提到这些年他的这些好运,”不是偶然的,而是一定会发生的。” 他这么说的。略嚣张,不过有嚣张的资本就显得很酷了。

信息过滤

在提到信息过滤这一点,xl是挺不屑的。他介绍了他使用 twitter 的经验: fo 了18k人。 看到这个可能会觉得很不可思议,当然,如果你是一个个fo 的话那确实太吓人了,没错,他就是自动化fo的。 这样会导致 信息过载 问题? 这里他提到一个观点:

信息过载是无法解决的,该解决的问题是垃圾信息过滤

那么这 18k 的fo量,该怎么做信息筛选呢?
肯定得有靠谱的工具才行,这里xl 推荐了 hootsuite.com, 看了一下, 是一个twitter的客户端,不过目前看起来支持导入很多 sns 的feed。xl 提到他有一个宽屏的显示器,然后开着 hootsuite 并且做多个strem做各种关键字的filter,或者筛选一批foer来看。
那为啥要费大力气暴露在这么多信息面前,然后再做过滤,而不直接就选择自己感兴趣的人来fo呢?
这里主要阐述了一个思想:

不挑,不做预先筛选

这里xl 举了两个例子,一个是借鉴了计算机大师的名言:

过早的优化都是有害的。

另外一个是扯了一下 “剩女” 是怎么剩下的, “算数没算好。”, 筛选过多导致符合条件的人数小于一生中能遇到的熟人的数量。

好学不挑

这是我概况的意思。在扯到信息过滤,不预先筛选后。xl 提到自己兴趣广泛, 做事都是基于学习的乐趣,所以很有动力。
谈到跨界这个问题,有很强的学习能力并花足够多的时间去钻研,这就谈不上跨界了,所谓 行者无疆。 这里态度很关键,不能抱着随便的心态,就这一点他谈到当初很多人一起关注了比特币,但是大部分人都是玩玩心态,买卖几个币罢了,而他做足了功课下大力气投资,收获了这个意外的好运。大部分抱着玩玩的心态其实主要是真正的钻研学习都是不轻松的。 写到这里我其实挺好奇他是怎么找准方向,并能这么有精力去学习的。
那么该怎么学习呢?
这里有几条tip:

  • 假装会
  • 加倍努力
  • 足够的耐心

第2,3点都比较容易理解,第1点其实我没太明白。假装会把自己骗过去有什么意义呢? xl 提到可以在这个前提上来思考会的人的学习方式, 反过来理清楚到底有哪些需要补充学习的地方。

但行好事,莫问前程

这部分即是说执行这样一套方法论不能太有目的性, 意外的好运总会发生的。这跟我前段时间一直挂在嘴边的一句话 谋事在人,成事在天 挺像的。之前我的理解是把各种我能做的事情做了,剩下的就靠上天,靠一点运气了。在这一块 xl 还是举了挺多无心插柳的例子来支持他的观点的。

感想

大概如此,部分多了我的解读,可能有遗漏,曲解了些许意思。后来翻了 xl 在 rubychina 论坛的发帖记录, 感觉之前没线下接触一下这个神人多少有点遗憾。
目前我还没有掌握一门可以快速开发 app / 网站的 语言,除了公司的项目的话,没有开发过个人项目,虽然感觉这一切其实都不难的,但还没迈出这一步。看到 xl 老师这么牛逼的跨界,作为程序猿真感到羞愧。
知耻而后勇。

IPSC 2014

2012-06-16

今年的ipsc 昨天刚结束,跟3xian 和 larry 一起在3xian家,晚上七点到十二点,做得挺过瘾的。我们的队名是 Sucker Punch, 最终104名,b1 在最后节骨眼没有搞出来,还是有希望挤进前100的。下面简单记录一下比赛的经过吧。

Problem C: Copier
这道题挺虎的,说的是最初把一个1到N排列每次一段连续子串拷贝到右边,重复若干次后求原始排列。一开始我想暴力小数据来着,有若干限制。不过一看大盘不对,b2都好多人过了,然后想了下,发现从左到右数字的出现顺序没有变,于是瞬秒了。

Problem H: Hashsets
这道题即是让你给50000个数字,然后让c++/java 的 hashset 插入超过两秒/十秒。 3xian 没过一会就丢来一个 样例程序 ,照着搞一下就过了小数据= = 不过看起是针对java的,于是就没有交大数据了,大数据需要 c++/java 均超过10秒。看solution 看到一个 universal hashing

To Be an Ac Man

清明回学校一趟跟集训队的小伙伴做了一个小分享,主要是讲了一下我对做一个好的acmer 的理解,准备的稍显粗糙,slide 上的内容也多为大空话。anyway,share给大家,求指导。

另外吐槽一点就是 slideshare 居然被强了,太没天理了。

Big Cube

Big Cube 是今天(2014.3.15) 鄙厂第二届黑客马拉松我们队的作品, 我跟 yc 还有 cc 一起搞的。这个名字是我今天随便取的,我们要做的是一个 OLAP 的 demo。

前情提要

早在12年初我们就在寄希望 OLAP 来帮助数据仓库数据建模,数据解读与分析。当时我们采用的是 mondrian 当时的想法很理想,感觉就是创建几个模型,几个维度,事实,就可以在各种粒度下把各种指标囊括进来,并有统一的地方可以管理指标定义。 后面这个项目失败了,diao总结了一些失败的原因:

开发和使用太复杂, 成本太高
产品成熟度较低, 很多数据需求没法支持
笨重,不太适应互联网公司快速灵活的节奏

在我看来,当时采用的工具和方案主要还是太慢了,不仅是工具调研与应用,后期的模型开发以及工具使用同样。由于公司发展很迅速,大部分模型都不太稳定,新的事实,维度也经常产生,维度和事实本身也太稳定,部分事实发生之后还会修改。当时的 backend 依赖的是 mysql ,本身也不可扩展。

后来 ek 又启动了一个曲线救国的计划,ModelBuilder。这个工具是 ek 独立完成的一个跟 ETL 工具相结合的模型设计工具,通过配置模型可以在hive下生成各种主题各种聚合粒度下的统计指标。在我看来相当于一个自研的 OLAP 服务的核心部分。现在在内部使用也很好,负责的指标和依赖很多。

当然这次 Hackathon 我们使用的是 cubes 这个开源的 OLAP python 包搭建的。早在 12 年我们做 OLAP 的时候,我就发现这个 python OLAP 工具, 不过当时也只是关注,一直都没有尝试使用。这次比赛之前又看了一下,感觉拿来主义十分方便,简单的模型配置还附赠一个前端的模型展示 CubesViewer , 之前提到如果 backend 依赖 mysql 的话,那看起来还是不够完美,所幸 cubes 的 backend 是可以定制化的,其中 sql 类型的 backend 支持所有封装了 sqlalchemy 接口的引擎, 恰巧我们最近上线了 Presto , 看了一下 github,有人已经提供了 Presto 的 sqlalchemy 封装的包 pyHive , 看起来万事俱备了,于是我确定了 Hackathon 就搞这个吧,一个支持海量数据快速响应的 OLAP 服务 demo。

准备工作

在 Hackathon 的前几天我主要是负责前期体验的,这里我想搞清楚的是:
1. 模型表示上是否可以与我们的数据格式对接(或者需要生产新的数据来适应特定格式), 需定一个展示模型,最好有意义
2. presto backend 开发是否有问题(接口是否好用), presto 的SQL语法十分支持cube生成的查询
3. cube server 的性能是否符合预期
4. 前端是否需要再做进一步开发

在13号左右我开始在线下测试第一个 presto backend 的 “hello world” 的case, 发现生成的语句会包含 order by limit offset 的语句,而 presto 不支持 offset 类型的语句, 算是我们后续要解决的一个问题吧。其他问题基本没来得及看。

开幕

15号下午五点如期开场, 兴哥和荣均简单地做了讲话大家便更忙各的了。

14号进展

开始后我们把晚饭定完之后就开始分工着手解决问题, 这里我主要负责模型的选择与数据生成以及配置相关工作, yc 负责 cubeviewer 的适配,cc 负责 presto 相关的查询支持。我们就在自己工位上搞,一起通过 github 共享代码。一开始我打算配置一个较复杂的模型,不过深入去看,感觉还是得一步一步来,先搞定简单的才是, 于是我选择了一个仅有四个维度的已经聚合过的数据作为展示demo。 presto 这边纯爷着手解决 offset 的问题,兴致挺高的,打算在 presto 那边添加这个功能。yc 同学由于要去签租房合同,搞了一会儿就得提前撤了。话说这次我们定的是棒约翰的披萨外卖,挺好吃的,我一下子吃的有点撑。晚上十点我跟cc一起坐班车回家了, 我的进度是配置了一点点模板,cc还在解决 offset 的问题。这里我说的是这次我没有像上一届一样在公司通宵搞这个了,这段时间我一回到家就洗个澡感觉十分舒服,洗完澡之后可以支撑我工作到两点,然后第二天早上七点起来还很有精神。所有我在 Hackathon 也选择回家,洗澡然后第二天再过来。

15号进展
由于 demo 还没有成型,15号早上我六点就醒了开始干活了,感觉 presto 那边做修改可能比较困难,我就在 cubes 这边生成查询时将 order 和 limit 相关子句给去掉了, 算是做了二手准备吧,这样我们的一个简单 demo 才跑了起来。早上七点半我就出发去公司了, 十分兴奋。后面十点多的时候我们三个都到了,大家继续战斗,我让 cc 来一起配合模型编写以及一些前端展示的润色工作,yc 同学还在搞 cubeviewer, 后面他发现一个大bug : cubeviewer 使用的 cubes api 跟最新的 cubes 不兼容 ,当时差点崩溃了。 yc 同学说,"给我两个小时,我把这个bug fix 一下" 。后面 yc 还真的在约定时间内搞出了 api 把 cubeviewer 跑起来了。我们在一旁帮忙测试,发现还是有几个问题:
1. 维度数据没有正确展示
这部分初步猜测是由于 cubeviewer 使用的数据格式同样是老的,导致部分假设面对新的数据格式失效了,导致维度相关数据没有正确展示。
2. 做 filter 的模块没能正确执行
这里我们后面发现是由于 filter 模块的 SQL 模板产生的 SQL 不符合 presto 的语法规范,导致发起的执行失败。

或许还有更多的问题,不过以上两个问题的解决就很花我们的时间了,最终在下午两点半之前也没能很好解决,时间到了,只能硬着头皮上台演示了。

我们抽到了第四个演示,我简单做了四页 ppt,又开了两个查询页面展示我们的 demo,不过可能是演讲技巧的问题,异或展示demo不够清楚,感觉整体展示效果不好。后续我在台下听了后面二十来组的作品,大家的想法都挺出彩的,完成度也很好, 比上一届来说进步了很多。最终我们毫无悬念地没有拿到奖项,anyway,我觉得能在短短的比赛时间内让最初的想法 work 我已经很满意了,后续还可以在这个点上继续开发,可以期待后续给用户提供这样遍历的分析引擎是非常牛逼的。

后续改进

  • 将 cubeviewer 调通, 调整 sql backend 查询语句生成让 presto 支持相关查询
  • 测试 model viewer & model builder 组件, 方便观察和编辑model,可以做到自动 reload model 文件那就再好不过了。
  • 添加 label, 多语言支持(主要是中文)
  • 在适当的地方添加 cache

总结
本次 Hackathon 由于有强大的队友的加入,再加上确定的计划与目标,故一切尽在掌握当中。当然时间还是没能有剩余,没能达到最佳状态。我看有些组的作品其实也不全是这两天的工作,不过感觉也无可厚非,毕竟牛逼的想法本来也不是一天之内就可以很好的 prototype 出来的。下次也许我们也可以这样来,多做一些准备工作,尽量想清楚所有可能出问题的地方以及相应的解决方案,这样在实际动手时才不会慌张。

后记
又看了多年之前的 mondrian, 发现现在它貌似也很牛逼了,后端也支持很多 SQL backend: 支持 impala , presto , red-shift 。部分还属于初步阶段,不过应该也是激动人心的提高,比12年好多了。

数据仓库的一天

标题党,"数据仓库的一天" 是鄙厂刚刚结束的第一届 hackathon 我们小组的项目,我,cc 和 cjz 。

hackathon
鄙厂的 hackathon 在几个礼拜前就已经宣传了,不过我开始组队, 确定好做什么却是在最后几天。主要还是自己平常缺乏培养捣鼓的能力。当有得力的cc和cjz加入后,感觉我们应该可以交出一个不错的东西。在思考做什么的时候,我们已经看到有许多不同方面的创意,比如zg同学想做的 “Smart SQL Editor”, 章爷的类 “wolframalpha search” 的 “data knowledge engine”, diao的实时销售额展示和更多的数据可视化作品。思考初期我并不打算做什么可视化的作品,一直在想能有没有什么更有趣的想法(可视化肯定一堆人做)。不过从自己的idea pool中没有找到什么可喜的东西,后面cc提了做数据库数据流向方向的事情,其实也是可视化的东西,不过我感觉这比一大堆地图上的可视化还是更有趣了一些,当然也更难做。于是比赛前一两天我们就在一堆的数据库可视化资料中寻找适合自己的表现方式。

前期准备
我们首先看到的是一个 hadoop的数据流向可视化作品 ,感觉还蛮酷的,不过具体细节什么的都丢失了。这里就是我的担忧: 数据的布局该如何处理。在传统的地图方面的可视化作品,作品上的每一个点都有明确的地理信息。而在我们考虑做的数据库数据的流向作品中,数据库中的数据该如何组织是个问题。这个问题我们从一开始就没有仔细考虑清楚,也不可避免导致我们最终的作品的混乱风格。在比赛前一天晚上我们看到 twitter 员工的一个不错的的hackday作品 hdfs-du , 在 hdfs 这个文件系统上提供一个可视化的作品, 简单但却非常实用。 另外我们看到一个可视化方面是 heatmap ,感觉在可视化中中添加热图的概念是锦上添花的。在这两个基础上我想到了一个改进点:

可以在 hdfs 系统上做实时的访问展示,使用 treemap 来展示文件系统,确保展示有层次。然后实用 heatmap 来做实时的文件系统的访问热点展示,将每个时刻哪些数据被访问展示出来。这里的可以写一个异步抓取程序去抓取并分析 hdfs 上的 MR任务(可能不太全,不过具有代表性)。

不过 cc 同学觉得 treemap 太丑了,另外比较想做数据流动方面的展示,我们在展示文件系统还是展示数据表这个基本问题上也没达成一致,于是我的建议没有被采纳。在 hdfs-fu上我们看到 voronoi-treemap 挺酷的一个东西。我们当时认为拿那个来展示表也许是一个很酷的展示。最终我们达成一致的是 在时空两个维度上展示数据仓库的表为准,在实时的基础上尽可能添加热图和流动的概念

开幕
就这样在一切还没有很成熟的情况下,我们在9月6号下午5点迎来了 hackathon 的开幕。

前期
开始简单的分工是我搞后台数据支持,cjz 搞heatmap/射线相关的研究 , cc 搞前端展示支持。我一开始先准备基础数据,比如表信息以及依赖关系,这些东西从元数据中是很方便获取到的。与此同时cc同学调研 voronoi diagram 的展示,希望能将所有表展示在这之上。当我们做到第二个小时的时候,cc 发现 voronoi 似乎不太能胜任, 似乎这个图不太能表现表的大小关系(虽然此时我还没有取到这个数据)。当时我们认为不能取到大小关系是不能接受的,于是我们转向其他的展示。cc 后面考虑使用 d3 的force layout 的一个 node 展示 。这段时间就是我跟cc在初始化数据上的一些联调, 由于数据量实在太大,调了很久也没有很满意的展示。cjz 那边 heatmap 看起来很方便使用,不过射线的话暂时没想好怎么搞, 而cc 找到的一个可视化作品 wbca 实在太炫了,也让我们非常想尝试添加上射线。 两个小时后我主要是在提供所谓数据流向方面的数据,这部分我一开始是简单做的,跟 cc 简单商量我来提供一个时间段内发生的数据移动事件。由于我们要展示所谓热度这个概念,于是这里得定义一下。前期简单做的话我直接使用ETL相关日志,通过ETL来还原表级别的数据流动。将当前时刻正在进行的ETL流程找出来,并跟进执行位置确定执行百分比,后续可以以这个百分比来做热度数据。其实这里热度的定义并不准确,没有太多含义,仅仅是为了展示做了一个相关的百分比罢了。我简单将数据提取出来后,观摩了一下 python 的 flask 做了一个简单的api服务。这里我并没有马上就考虑实现实时的部分,而是打算看到第一个 demo 再说。

第一个demo
我们实际上做出第一个demo的时间比预期的晚很多,我在后端方面的粗糙工作很快就完成了,而前端关于热图和射线方面的问题还比较多。这段时间我基本没有产出,这是本次比赛的一大败笔,我没想好这段时间该做什么,现在看起来也许是反思一下我们的目标定制是否有问题,一些概念是否有问题(比如热度),是否需要及时修正。在呈现第一个demo的时候还有一个小插曲,由于 js 不能跨域访问,我跟cc的前端作品必须揉在一起。于是我在找 flask 如何访问静态文件上费了一番功夫 , 这里让大家看笑话了,主要是我平时总觉得这种东西肯定很方便google到,临时去找的时候搞的手忙脚乱。在大约第7个小时左右我们才有了第一个demo: 随着时间流逝展示数据仓库一天中表的热度(其实是访问情况) 。 展现效果并不好,没有实时,没有射线,热图展现过卡, 更多的还是数据layout不太好。这个时候大家还是在想如何把前端展示搞得更好,都扑上去搞前端了,没有冒出其他想法和其他改进。现在想想当时我可能应该往实时数据支持方面考虑一下,这样可能会跟加分一些。

射线没有搞定
在尝试一番无果之后,我们关于射线的展示宣告失败。这时候感觉士气不是很好,我们展现的只是一个一大堆圆圈然后随着时间变化的热点。关键是这里没法说故事,这里的热点没法自解释。这段时间我主要是帮他们做点前端打杂,比如添加一下title,添加一下热点label, 添加一个当前时间什么的。cc和cjz还在研究射线相关的技术问题,最终没有搞定。看起来我们只能交一个半成品了。在第二天早上cc希望尝试删减表来达到获得更好的数据布局,不过数据过少时整体展示也不美观,没有达到希望达到的层次效果。后面我们基本没有动力做其他改动了,时间也很快过去。

比赛结束
在7号下午两点比赛最终结束了,我们基本以第一个demo的状态结束了本次比赛,有点无奈。本次我们在前后端的配合出现明显的问题,主要原因还是作品的展示定位过于高端,为了达到炫丽的效果需要深厚的前端经验。后面在作品展示时,观看其他组的数据可视化作品, 虽然不够炫目,但在细节方面都有细心刻画,反观我们自己就是一团乱麻。hackathon 除了可视化方面还有其他很有趣的作品,其中不乏解决了公司实际面对的问题的作品,也有很多产品,rd组合的创意产品产生。Anyway, 这是我们第一次 hackathon 比赛经历,有一个有点挫但是能用的 demo ,enjoy yourself即可。

心得
若说有什么心得,我想了想有以下几点:

  • 提前想清楚,确定定好做哪一方面的事以及一些重要问题的提前准备,达成一致。
  • 在做的时候需要不断沟通,当遇到困难时如不能及时解决得想办法折中,调整方向。
  • 数据可视化产品需要设计,不能马虎。

后续可以做的改进
列一下几个可以改进的地方:

  • 实时访问
    一开始我们是希望做成实时的数据展示,不过最终没有去做罢了,这部分并不难。不过想到这里我感觉似乎这里"流动"不是很好表示了,而热图倒是完全适用,这跟我最初的设想一致,不过从文件系统下降到数据库的表罢了,这层下降可能在业务层面上会更直观。
  • 寻找更好的数据组织方式
    数据组织方式还是一大痛点,太多的表只会带来混乱。

Ref
A day in the City
wbca
Tweetping

Keep Updating Your Cv

2013-04-21

2013.7.26 update
知道什么呢,这件事情我直接拖了三个月,哦,这三个月我都干什么了,真该封我为拖延症冠军啊。 anyway, 还是继续写吧, move on。希望这次可以写完。

有一种观点我很赞同,就是要持续更新你的简历。

为什么要持续更新简历呢?

首先做一件持续的事情很cool,有积累,有收获。
维护一份简历可以让你看到工作概括,看到与牛人的差距( always benchmark against the best )。
维护一份简历可以让你在找下一份工作时不会手忙脚乱。

在毕业之前我总共制作了中/英文两个简历, 其中中文是用 word 制作的,英文的话是用学长留下来的 latex 模板制作的。在找完工作后我基本没有维护过简历了。作为一个希望能够持续总结的人,面对着停留在两年前毕业的简历,感觉是不能忍了。 我们不仅要认同一种观点,还要亲身去实践才算, 于是我开始实践更新简历这件事情(从写下这句话的三个月后,god)。

如何更好/方便地维护简历呢?

要做到定期维护简历的话,每次更新简历的代价就不能太高。良好的简历维护应该能够做到:
关注内容而不用在意展示
最好是文本编辑,方便版本控制和追溯

latex 版的简历看起来赏心悦目, 不过制作起来稍显复杂, 也不容易维护(latex菜鸟意见= =)。word 就更不用说了,排版不是很容易,也很难做版本控制。
考虑维护简历这是一个长期的过程,我希望更新/生成简历能尽可能快且保持高质量。
于是我考虑是否能用 markdown 来写简历呢。 确实发现很多文章介绍用 markdown 来写简历。

使用 markdown 来制作简历

鉴于有使用 markdown 的习惯,于是很自然地考虑到使用 markdown 来写简历,最开始在 github 上看到 mwhite的resume 项目看起来还不错。这里使用到一个好东西,叫 pandoc,可以在不同文件格式之间转换。比如只写了markdown 版本,可以转换成 html/latex, 看起来挺方便的。不过原仓库的排版不太喜欢,改起来又似乎有点麻烦。 同样还有一个 icco的 Resume 也是同理,写 markdown 然后 host 到 github 上之类的, 相比之前其排版会相对美观一点。
编写 markdown 可以直接在 vim 中敲敲打打,也可以是用 Mou ,一款十分好用的 markdown 编辑器。

markdown 有什么问题呢?

我遇到的问题是难以把漂亮的 markdown 转化成 漂亮的 pdf,直接从 markdown 转换成 pdf 会出现各种边距问题。在努力尝试一番未果时,后面我退回到 latex 了= = 不仅做 markdown 还做 latex, 然后 pdf 版本简历还是用 latex 出吧。mac 上我安装了 mactex 来编写 latex, 基本的节奏还是在找比较好的模板,然后填上自己的内容。

如何编写你的简历?

当工具本身的选择搞定,剩下的就是内容和排版了。
在内容方面, google reusme 第四章中给出蛮多中肯的建议。
工作经历是简历中一个重要组成部分,在介绍过往工作时, 要注意以下几点:
成就导向
主要以你完成了什么而不是介绍你在做什么,这里即突出你的贡献而不是你的职责, 而且应着重突出重要贡献(bullet)。
量化结果
量化你的贡献,用数据说话。

至于排版方面, 有几个建议:
干净, 专业,一致
体现在统一间距和对齐上,简单来说就是要看着漂亮,顺眼。
控制在一页简历
简历控制在一页纸上方便阅读,太长后面部分基本也没有pv。只放最相关的重要部分。
突出亮点主题
理论上越有亮点的部分放越前面效果越好,但考虑到主题前后条理性还需要做一些适应性调整。一个明显的例子是如果教育经历不是很出彩,可以考虑将其往后挪。

当然以上几点我也基本没完成,只是比较赞同。

我的成果

初步做了 markdown版本latex版本的简历 , 目前 Experience 展开略细,还需进一步改进。 简单观察,很容易就发现目前我简历的问题:
工作没有亮点, 参与而不是推动
技术能力没有杀手锏
没有个人项目

没有做得很漂亮,发现问题就想办法去改进吧:)

ps:
又是一件拖延了很久的事情,大概是从今年二月份开始就想做了,每天对自己念一遍我要把这件事情搞定,于是可以搞定,感谢sean。

Ref:
markdown-cv
beautiful-resumes-with-markdown-and-latex
google reusme
shenfeng’s cv
mijia’s cv
如何做简历

Query Evolution

2013-04-04

从最原始的查询开始,位于后台某个报表,当用户发起一个查询,我们该干啥呢?

抽象一种最简单的形式,查询是对我们的数据做一定的转换而得来的,即

按这样的理解,当用户发起一个查询时,我们可以直接在原始数据集上进行操作, 操作的过程可以在服务端或者客户端。

直接在原始数据上操作查询数据是非常艰难的,业务方面的数据并不是那么查询友好,有多个查询需求时得重复很多重复的代码和计算。

于是我们很容易想到上述的模型需要再添加一层预处理层,方便查询。

在实际处理当中,我们本着依靠数据仓库理论武装自己的原则,对原始数据做了系统的预处理后形成了一个数据仓库。

由于引入了预计算,就有了一个数据更新问题。为了抠那一点时间和空间,我们绞尽脑汁想到了一种所谓增量更新( incremental update)的方法,于是数据愉快地更新起来了。

机器或者人工的失误,数据源数据发生了错误或遗失,对于我们的预处理层真是一次灾难啊,没什么好说的,只能重算了。

由于数据规模逐渐增加,单机的关系数据库渐渐扛不住了,我们只能引入分布式的处理(mapred)来分担预处理的压力。

在分布式计算模式下,原有的关系数据库特性已经不在那么好用了。索引剪枝不再好使,增量更新也不易于实现,于是大部分情况下,我们粗暴地全量计算,我们再也不怕历史数据有问题了。

随着预处理数据渐渐地迁移,不可避免地我们需要查询分布式数据库(hive), 这样我们的查询必须支持那种异构的数据源了,我们可以再加上一层,把各类查询都接入。

我们称这个新的服务是查询中心,它将作为一切查询的入口,也体现了一种服务化的理念。

当然,各类的查询区别明显,普通报表query 和 api 一般执行快,要求响应也快。对于用户发起adhoc 操作,则可能查询费时也不一定需要及时响应。对于这样一个包容性的服务来说是个考验。

似乎漏了几部分?

  • 由于有了预处理,查询数据的实时性不可避免要打折。
  • 对于分布式数据库数据访问有点过慢(目前的策略是将聚合结果写回关系型数据库来支持快速查询)。
  • 数据应用方面,推荐/搜索相关的线上查询服务设计
    • 感觉支持后台数据服务和线上服务还是不能混在一块的

这些都是可改进的点,围绕着查询这个主题。

Create a Python Package

在简单做了一个类 hiveserver 的thrift 接口后,担心日后接口更新,我又添加了一个简单的python client包(没有照顾其他用户= =)。作为要分发给用户使用的包,我需要将其打包发布, 然后才好分发。

参考 The Hitchhiker’s Guide to Packaging 文档简单了操作了一下,倒也不麻烦。

目录结构:

package tree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├── CHANGE.txt
├── LICENSE.txt
├── OpenHiveClient
│   ├── client.py
│   ├── __init__.py
│   ├── openhive_thrift
│   │   ├── __init__.py
│   │   └── openhive
│   │   ├── constants.py
│   │   ├── __init__.py
│   │   ├── OpenHive.py
│   │   ├── OpenHive-remote
│   │   ├── ttypes.py
│   └── openhive.thrift
├── README.txt
└── setup.py

其中 OpenHiveClient 即为要发布的package, 其中的子目录 openhive_thrift 为 thrift 生成的文件。

setup文件内容如下:

setup.py
1
2
3
4
5
6
7
8
9
10
11
from distutils.core import setup
setup(
name='OpenHiveClient',
version='0.1.0',
author='code6',
author_email='wuzhichun@meituan.com',
packages=['OpenHiveClient', 'OpenHiveClient/openhive_thrift', 'OpenHiveClient/openhive_thrift/openhive'],
license='LICENSE.txt',
description='open hive query client',
long_description=open('README.txt').read(),
)

部分meta填写较随意,无影响。使用 distutils, packages一项似乎得写出所有的包,有点繁琐, 使用的是 setuptools , 有自带一个 find_package 的方法,那样写比较方便~~~

如果要打包的是单文件的话可以使用 py_module 参数。

后续执行 python setup sdist 可生成发行包 OpenHiveClient-0.1.0.tar.gz , 可直接使用 pip install OpenHiveClient-0.1.0.tar.gz 安装, 如果需要更新安装包但没有改版本号的话可以使用 -U 强制刷新。

目前敝厂没有私有pypi服务器,所以为了一个包搞一个的话没必要,一种方式是可以挂在公开的地方比如github之类的。 挂在 pypi 上的问题是不能上传覆盖相同版本号的安装包。这也很合理,应该是开发到一定程度才发布稳定版才对,跟我们在代码仓库上一修改就发布的节奏是不太一样的。

当然,上文都是指要做一个分发的包,如果是部署自身线上服务使用的包,完全可以直接放到代码仓库中同步到线上然后直接安装。

打成包的好处是将独立于业务的模块抽出来后方面引用,可以避免加上一堆 sys.path.append 了, 当然维护成本稍有上升。

附录

http://guide.python-distribute.org/creation.html
http://woodpecker.org.cn/diveintopython3/packaging.html
http://www.worldhello.net/2011/03/14/2357.html
http://www.ibm.com/developerworks/cn/opensource/os-pythonpackaging/index.html

Open Hive

2013-01-05

有时我说的话就是放屁,这已经都到 12月 1月了。不过我还是厚着脸皮来了,我还是希望写写的,每当我来refer自己干过的一些事情的时候, 还蛮有用的。

今天我想说的是近期我们在做的一个事情,说来也简单,往往我觉得难的不是要写多高深的代码,而是采取什么方式来达到一个目的, 满足需求。我的条理还有待加强,暂且这样。

对于做数据的团队,一个很重要的事情就是开放数据,怎样提供一个更好的环境来让更多的人来访问数据,获取他们关心的内容。如果数据始终是仅在团队内部可以使用,那么势必会增加很多重复的无谓的体力劳动。在开放数据这一块,之前大家做了一些努力,有了一个内部的自助查询的系统,面向RD和一般的分析人员。开放的方式是提供一个窗口让用户写具体的SQL来查询,返回查询结果, 并可以定制很多图表。 系统内开放了若干链接,每个链接可以查若干表,并可以看到表相关的字段信息。一般来说这样就够了,当然写SQL门槛稍稍有点高。

之前主要数据都是在 mysql 上,开放的方式也非常简单, 只需要提供一个从库即可, 让查询都落在从库上,然后主库进行更新。当我们在mysql撑不住,逐步迁移到hive的同时,自助查询这边相应的也需要改进以支持hive查询。虽然已经有包括 hwi( anjuke的改进版hwi ) 和 phphiveadmin 以及 hue(我们用apache hadoop, 用不了cloudera的产品)了,感觉跟我们自己的查询工具结合在一起会比较方便使用。结合的方式也比较简单, 简单使用hive cli的执行方式来查询并保存结果数据即可, 大致如下:

run hive query
1
hive -f /tmp/testsql 1>testsql.output 2>testsql.err

这样把查询结果放在临时文件中,然后再展示给用户。另外由于hive查询一般比较久,故只能做成异步查询。

这里为什么不用hiveserver呢? 感觉hiveserver在我们这边使用总有一些问题,使用hive 0.9 配合zookeeper时,hiveserver看起来会泄露zookeeper连接,导致一段时间后就不可用了。 当然也可能是我们的姿势不对, 不知在 hive 0.10 上是否会好些。

开放查询做到这一步其实基本差不多了, 用户可以自己执行查询并查看/下载结果集。 但我们在这一步的时候却还不能开放,觉得对用户的控制还不够,用户权限太大了。 说到这一点,我们目前的hadoop/hive环境上只有一个默认用户,其余用于查询的用户(比如apache)基本上对所有表都有查询权限。另外一点是我们线上的hive任务也在定期执行,自助查询这边不应该占用过多资源。在一些必要场合下我们必须有能力干掉用户的查询。简单来说,初步开放,我们需要做到:
必要的权限控制
库/表级别,语句类型(限制只能使用select),这些控制可以跟账号绑定。
资源限制
任务同时可以起的map数量和reduce数量控制。
锁限制
自助查询不能争用线上任务的锁。

  • 必要的权限控制
    在做权限控制的时候本来想直接用 hive.security.authorization.enabled 参数来搞,发现当所有用户都拿一个账号(apache)来访问是没啥用的= =, 没办法,只能手动搞了,于是比较糙地搞了个类似的自己用, 表如下:

hivetablepriv
1
2
3
4
5
6
7
8
9
10
REATE TABLE `hivetablepriv` (
  `grantid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '授权自增ID',
  `rolename` varchar(128) NOT NULL DEFAULT '' COMMENT '授权角色名',
  `dbname` varchar(128) NOT NULL DEFAULT '' COMMENT '授权库名',
  `tablename` varchar(128) NOT NULL DEFAULT '' COMMENT '授权表名, *表示任意表',
  `modtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '记录修改时间',
  `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0为正常授权,128为已删除授权',
  PRIMARY KEY (`grantid`),
  UNIQUE KEY `rolename` (`rolename`,`dbname`,`tablename`)
) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8 COMMENT='hive开放查询权限表'

然后在实际查询的时候,使用虚拟角色来访问,解析一下查询语句使用到的表(简单正则),然后进行一下权限判断即可。

  • 资源限制
    这步可以很简单做,比如直接在 Hadoop Fair Scheduler 配置一个受限的队列即可, 基本可以保证资源限制。
  • 锁限制
    我们打开了 hive.support.concurrency 并使用zookeeper来进行锁竞争,主要是防止线上日常ETL程序执行过程中对资源有竞争(比如一个表在更新时有流程访问),这里在自己查询避免争用线上任务的锁只需要关闭此开关即可。

综上, 我们仅需把执行语句加强一下:

run hive query safely
1
hive --hiveconf hive.support.concurrency=false -hiveconf mapred.queue.name=slow -f /tmp/testsql 1>testsql.output 2>testsql.err

另外权限控制我们在查询脚本执行查询之前做。我们还缺的一件事情是记录下用户的查询(logging)。这一步也可以简单在hive执行脚本中收集。为了能够更好的监控这些任务,我们还需要能够将查询和其所起的任务关联起来。这里使用了一个比较土的方法,就是边执行边解析程序的标准错误, 收集日志中提到的起的hadoop jobid。有了这些信息之后,就可以将一个查询所对应的任务干掉了。

这样我们只靠一个简单查询脚本就可以基本的给hive查询一个具有较好约束的执行环境了。这个openhive脚本可以直接给自助查询工具查询hive使用。不过对于其他RD有需求查询hive数据的,我们还得暴露一个较友好的接口,比如使用 thrift 做一个服务。想到这边我又想到 hiveserver 了, 感觉我的想法有点多余。不过还是那个问题,我们希望有更多控制,然后又不太想在hive源码上动手脚(觉得麻烦以及以后升级比较有问题, 当然主要是我对java不熟),所以搭 thrift 然后背后用调用 openhive 脚本来实现, 接口可以这样:

openhive.thrift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct Query {
  1: required string query,
  2: required string username,
  3: optional string password
}

exception OpenHiveException {
  1: string message
}
service OpenHive
{
  # Execute a query. Takes a HiveQL string
  void query(1:Query q) throws(1:OpenHiveException ex)
  # Fetch one row. This row is the serialized form
  # of the result of the query
  string fetchOne() throws(1:OpenHiveException ex)
  # Fetch a given number of rows or remaining number of
  # rows whichever is smaller.
  list<string> fetchN(1:i32 numRows) throws(1:OpenHiveException ex)
  # Fetch all rows of the query result
  list<string> fetchAll() throws(1:OpenHiveException ex)
  # Fetch Query header
  string fetchQueryHeader() throws(1:OpenHiveException ex)
  # Fetch all query log
  string fetchQueryLog() throws(1:OpenHiveException ex)
}

整个接口基本是 hiveserver 的子集= = 服务端简单使用Python来搞,使用thrift的 ProcessPoolServer 类 ,其原理是server启动时fork出N个工作进程,进程之间不影响且可以重复使用。 这样遇到的问题是服务器的处理有瓶颈,每次最多同时处理N个任务,来多了会阻塞,目前我暂时将N设置为10。后续完全可以做成异步的形式,当然得修改接口,比如添加一个 sessionid 的概念。后来跟同事商量,其实对于hive查询本身server端是没有什么压力的(主要在hadoop集群上), 故基本不需要考虑 python GIL 问题而使用多进程。另外他建议使用 gevent 来提高server的并发能力,当然这样瓶颈就落到后端查询上了,感觉还是需要一个队列的机制,倒是可以试试。

大概就是这样了,废话了很多其实内容很少,也很简单。条理和叙述方式有待加强,终于又写了一篇blog,欢迎交流反馈~~