这些年,我工作上走过的路
常常的,我会感恩于我所在的公司,让自己经历了种种。很多情况下,公司的成长带动了自己的成长。完整的跟着公司经历大数据业务从无到有,从有到精,这种历程就像美味的食物,吃过了才能真正感觉,而文字是不足以表达的。
我走过了毕业季,创业征途,踏进开源之路,转型进入大数据,到最后有缘接触机器学习。每个章节,我都会提及对应那个阶段对技术的感悟,自己做的一些具体事情。
到写这篇文章为止,我发现经过这八年,我依然没有懈怠下来,我依然在狂奔。
毕业季
2008年12月,清晨的阳光有气无力的铺在了一片没有经过打理的草地上。有了阳光,没了打理,自然成了杂草儿们的天堂,千奇百怪任性长着。阳光顺着草地,扶着墙翻过窗子,跃进了阳台。阳台左边是洗手间,前方是一个虚掩着的门,到了这,阳光止住了它慵懒的脚步。大学的宿舍是长方形的,四个边角都放着写字台和床。说是床,其实就是写字台上的一个挡板。海南蚊子多,所以挡板上都是有蚊帐的,蚊帐带来的坏处是,如果蚊子进去了,它除了烦你也别无出路,好处是,可以形成自己的一个小牢笼。我睡眼惺收,散发着一丝颓废的气质。颓废在这是一种赞美的词,只有艺术家才能配的上颓废这个词。当然,我不是艺术家,所以放在我身上,也就是真实颓废本意解释了。很快,我会热血的成为几百万即将毕业的学生,被学校撒豆成兵,最后可能成为炮灰。
我确实成为了炮灰。
刚从深圳铩羽而归,原本希望能在深圳找份工作,但落了空,完全没有门道,愣头愣脑的去了,愣头愣脑的回来。期间十几天,一个面试的机会都没有捞到,深圳现在也是完全不记得什么样子了。
这种感觉,想必和艾伦第一次去和巨人战斗的情景是一样的。
框框框,有人敲门,我们没搭理,接着他在门外问:有个公司来学院招聘,是招计算机的,你们要不要去看下。
我饿了,真的饿了,我没做任何思考,便起床动身。原先困倦的大脑脑功率趋近于0,现在瞬间飙升。恩,是脑功率,不是荷尔蒙。
那个时候自己就像一只农村的土狗,只要有份工作就行。而且如果纯粹做个码农,我还是很自信的。大学期间我就已经定了方向,专攻Java,所以或多或少还是有些积累,毕设的时候用Java写了个程序,给磁盘建索引,用的Lucene,顺利过了毕设。没想到的是,我竟然因此和搜索结缘,一直持续到今天。
创业征途
突然来的机遇就是这么神奇,也让人感觉莫名其妙,说来就来了,你真的不知道为什么会来,但真的就是这么来了。
当机遇来临的时候,常常让人懊悔的是抓不住。但抓住了,也未必会让你成功。但是,这是一个不管成功或者失败,都让你收获满满的一次机遇。
这是一家创业公司。我去的时候一开始只有三个人,A君,B君,还有我。
A君多才多艺,产品经理+UI设计+投资人,B君和我则同为技术合伙人。
在找到我之前,A君和B君已经在海南师范大学旁边的一栋写字楼租了一个办公室。现在回想一下,或许我们应该租个地下室,成功的概率可能会更高些(不过,如果去美国的车库或者地下室,应该成功率又会提高)
就这样,08年12月开始了我程序员,或者是创业的征程吧。
我们做的是一个原创音乐站点。
这期间我们常常每天工作13-14小时。要知道,那个时候我们没做过任何项目啊,只是大学看了几本程序设计的书,而真正做出一个产品,需要掌握的东西却是是非常多的。
但是热血和时间这东西,真的是有用的。就这么着,基于热血的推动,时间的磨砺,渐渐的,一个原创音乐分享网站竟然慢慢开始开始有模有样了,整个过程,我们自己设计,开发,购买服务器,托管,运维,运营。
作为一个流媒体音乐站,不同于一个简单博客,尤其是对于我们几个没有什么技术积累的年轻人而言,其挑战是非常大的。
流媒体服务器,Web端Mp3播放器,音乐上传,音乐转码,音乐下载,个性化主页等等,挑战非常多。B君后期专攻页面和JS,我想,他现在能够开发Web端操作系统,也得益于这次的挑战的吧。
首先是站点搭建,没有采用Worldpress之类的开源组件,真的是从零直接从头开始做的。那个时候不知道原型设计工具Axure,A君就直接用Photoshop把界面画出来,然后把一些小ico切出来给我们用。A君虽然没有做过产品经理和UI设计师,但是他设计出来的界面真心大气(08年的时候),后续我们的对手,原创音乐中国,还有那有个因为涉黄被关闭的一个网站,都在我们上线后不久改版,我们对比过,明显借鉴了我们的设计元素。
我和B君大学学的都是Java,于是采用了SSH2开发。从头开始垒代码。还是那句话,如果只是做个类似博客平台的站点自然是不难,但我们做的是原创音乐分享网站。这里面涉及到如下几个难点:
-
首先我们是个音频流媒体网站,需要搭建流媒体服务器,以及播放音频的客户端
-
接着这是针对音乐人的一个社交网站,有点类似现在的微博,音乐人上传了大量自己的音频,需要大量的粉丝以及与之互动。所以需要提供一个酷炫的个人主页,QQ空间是一个标杆。
于是经过仔细研究,我们使用了Red5 搭建了音频流媒体服务器,实现了一个简易的 flash 音频播放器,暴露js调用接口,使用Js进行控制。
个人主页我们花费的精力非常多,09年时,我们就已经仿照QQ了,允许换肤,自定义布局,这个对前端以及后端要求都挺高的。后面B君在做后端服务的时候,也同时成了一个前端高手,我可以说,他已经精通CSS和JavaScript了。(后来B君来了北京,后续又去了香港,在香港时,已经可以用JS开发Web操作系统了,这是后话)。 整个页面任何一个版块,你都可以显示,隐藏,互换位置,设置不同模板。
作为一个流媒体网站,上传音频是个很重要的东西,为了显示上传进度,我们当时就折腾了好一会,接着遇到转码问题,使用了ffmpeg,设置要把转码进度也显示给用户看。
到后来,我们已经做了一个类似虾米这种音乐类的网站很多功能了,比如给出音乐列表,自动播放,直接在title上显示播放进度等等。
SSH2 给我的感觉就是慢,调用栈太深了。作为一个互联网应用来说,真的不适合。但是架构已经选定,也没办法。于是我们通过大量添加缓存的方式解决性能问题。
有大量的资源,自然就需要搜索了。为了方便查找歌曲,我们引入了基于Lucene的Compass。可以直接基于数据库建立lucene的索引文件。一般这种东西,很难用好,或多或少都有问题。我期间就经常各种错误,各种问题,不堪其扰。
到10年的时候,我们的歌手用户只有几千。但是歌曲数量以及总文件大小已经相当可观了。我们在各个细节进行了非常大的努力,比如歌曲,用户评论,可见不可见,上传进度,页面设计等等。
产品我们觉得问题不大了,可是,可是我们该怎么推广运营呢?完全没有门道。而且从08年到10年,差不多一年半,我们是完全没有盈利的,只是在烧A君的钱。
如果有了一定的用户量和活跃度,其实关于盈利的形态我们都是想好了的,当然这个也是借鉴国外的模式。而且我到现在都认为是一个好的模式。
但是我们感觉我们快撑不到那个时候了。我们那时候也没有投资人的概念。在海口,互联网行业是相当不发达的。不像现在,你拿个想法,跑到咖啡厅,就有人会听你讲。
于是我们展开了自救行动。10年团购很火,于是,我们打算先暂时放下手中的主业,做起了团购。但是后面我们才知道,团购初期是很烧钱的,不是我们能玩的起的。
海南是个旅游大省,于是我们开始做旅游站,但是啊,旅游要有线下资源。
急了就什么都尝试了。
2010年10月国庆期间,基本上宣告了创业的失败。海口有个奇特的天文现象,就是凡是国庆七天,那是必然下雨的。这个国庆也不例外,整整七天都是雨。我当时是个E站的一个老用户(只是看文章的老用户),看到了E站正好招人,但那个时候招的是Ruby程序员。于是十一前的一个礼拜,我弄了一本敏捷开发的书,然后把58同城的UI扒下来,然后用ruby on rails 写了站点,包括抓取,包括显示等。当然,没有后台。整整做了一个礼拜,然后把它作为示例代码打包,发给了E站。 后面就接到了E站老大的面试电话。
E站的老大看了我的代码后,让我很顺利通过了电面,问我是否可以直接去北京。我当时心想,偶像就是偶像,看代码就能看到我的能力以及诚意,没有N轮面试的折腾。
走的那天,好像还是下着雨。当时我的生活已经非常窘迫了,一个好朋友赞助了我机票钱,我也在没有找到北京住处的情况下,就踏上了北京的航班(临走的那天,B君说他也在北京,可以给我落脚,当时那个感动),开始了我现在的工作。
北京的旅程-开源之路
起源
2010年10月15日,我正式在C公司入职。E站是C公司的一个子站点,用RubyOnRails 开发的。我一开始基于其上做开发。就这么做了一个月Ruby程序员,有一个事情就第一次改变了我的职业方向。
某天老大突然说,你不是以前用Java做过搜索么,公司主站点的搜索就交由你做吧。当时公司的搜索是外包给一家专门的公司做的。我自然很乐意的接受了。
后面经过一个月的开发,也就是2010年12月中旬时候,第一个版本上线了。当然这个版本可以说超级简单,就是用Lucene搭建了一个单机版本的搜索服务。老大很开心,还请我们去看了让子弹飞。
Web/ORM/ODM 一站式开发框架
因为我之前做过一段时间的Ruby程序员,一对比,我发现,Java的Web框架都太不好用了,Java的ORM框架也不好用,Java 的MongoDB Client 也不好用。于是我决定开发一套一站式Web框架。
正好除了搜索的任务以外,公司希望做一个全站通用的标签系统。当时在选型上,老大说用Spring,我当时说,给我点时间,我自己开发一套开发框架出来,老大说,你有信心做好么,我说有。老大给予了肯定的答案。
于是,2011年的有一段时间,每天早上六点我准时起来,光着膀子开始写代码(这个可以推测是夏天了)。写了一个Web框架,一个ORM框架,一个MongoDB的 ODM。 后面我问老大,名字叫什么好,老大说,就叫ServiceFramework。于是我便把Web框架叫做 ServiceFramework,ORM框架叫做 ActiveORM,MongoDB的 ODM叫MongoMongo。经过公司许可开源了出去。
相关介绍参考:
http://allwefantasy.iteye.com/blog/1631522
http://www.iteye.com/news/25793
项目地址: https://github.com/allwefantasy/ServiceFramework
从2011年开始,我一直在优化这个项目,到现在已经四年了。不过开源版本因为工作缘故,一直没有更多精力维护,并且无法进行推广。但是内部版本却获得长了长足的发展,作为一个针对API服务开发的框架,除了易用性以外,我一直重点做的是可运维。目前我所在的数据部门,已经完全使用了这套框架。
关于可运维,框架自身可以做到的:
- 接口 QPS 监控
- 接口平均响应耗时监控
- 接口调用量(如果是http的话,则是各种状态码统计)
- 内置HTTP接口,外部可通过该接口获取以上的数据
同时,框架日志信息输出默认包括:
- http请求url
- 整个请求耗时
- 数据库耗时(如果有)
- 响应状态码
还有一个比较核心的功能是,服务降级限流。ServiceFramework主要面向后端服务,如果没有自我保护机制,系统很容易过载而不可用。经过一定的容量规划,或者通过对接口调用平均响应耗时的监控, 我们可以动态调整 ServiceFramework 的QPS限制,从而达到保护系统的目的。
这里其实还有一个重点是,传统的方式是,容器包含应用,比如开发好的代码打成war包放到tomcat等容器中。新框架的方式是应用包含容器(内嵌jetty),一个应用服务就是一个纯粹的java application.
开发完这个框架后,我花了半个月时间完成了公司标签系统的开发。
索引系统 (暂时未开源)
当时老大看上了一个叫ElasticSearch的搜索项目,类似Solr。不过那个时候ES还非常的初级,我当时年少气盛,没经过任何测试就上线了,但是对其了解有限,上线后问题不断,当时索引量已经颇大,光索引文件就达到百G。一开始我将原始数据也store进了索引,瞬间IO飙升,服务直接挂掉了。接着我讲原始文件剥离,只存储索引文件,但是发现也扛不住,服务经常因为压力大而没有响应,因为ES有Failover功能,如果发现有服务当掉了,就进行分片副本迁移,直接把网络带宽占满(那个时候路由器都是百M的)。我就开始看代码,改代码,但是不得要领。当时ES的社区远不如现在活跃和成熟。
我后悔了,不应该没有调研测试清楚就上线。而且当时一直困扰我的就是数据更新问题。索引了后,数据很快变更,我这边必须想办法得到通知。
于是我决定另起炉灶,开发一个简化版本的ES,使其完全能被自己掌控。经过一个月的开发,第一个版本的我们称之为CS的项目完成了。后面使用CS替换掉了ES。服务再也不会轻易当掉了。
在一次ES的分享会上,我分享了CS。蛮多人还是感兴趣的。CS作为一个分布式索引服务,特点有:
- 分布式架构
- 支持索引数据分片
- 支持构建离线全量索引过程中合并线上新增数据的机制
- 支持数据热备
- 拥有一个剥离配套的统一查询引擎
- 支持模块化,组件化
关于这个项目的一些简单介绍,可参看:
http://pan.baidu.com/s/1i3qsoBF#path=%252FESCC%25233&render-type=list-view
中的 ES分享.pptx 文件
CS的核心是是查询引擎和索引存储剥离。一些高级功能,比如跨索引检索,结果二次排序,摘要提取,获取详细内容展示,都是作为模块放在查询引擎中。当然统一查询引擎最核心的意义还是在于可以快速更新二次排序的引擎。当然这还需要有一些其他架构做支撑。
有新的模块添加,只需重启查询引擎,而不需要重启索引存储服务。索引文件重新打开是非常消耗CPU,IO的,常常会造成机器负载瞬间飙升,导致很多搜索维护人员轻易不敢重启服务。在CS不存在这个问题。
12年的时候,我终于有伙伴了,以前一直都是一个人孤军奋战。我称为C君。C君后来参与搜索的优化。之前我因为对Lucene的一个误解,导致排序效果一直很烂,我一直不得要领。C君发现了这个问题,瞬间搜索排序就正常了。后来C君开发了一套新的分词引擎,现在已经是一个知名的分词套件了(可参考: https://github.com/NLPchina/ansj_seg)。基于这套分词引擎我们做了很多分析方面的工作。
索引服务这个项目前前后后花了我四年多的时间。现在策略层公用的组件已经包括 SQL,JSON,URL params,Mutil-Index,数据网关等。后面我一直从事数据架构和算法方面的专研时,索引服务也成为架构中非常核心的一个服务。
北京的旅程-大数据架构之路
到12年年末为止,应该说我做的大部分是项目层级的工作。13年年初,公司突然开始重视大数据了。于是我们部门人员由原来的两个人变成了五个人。加了两个刚毕业的学生D君和E君以及一个算法工程师F君。
F君也是对我影响很大的一个人,让我从此了解了机器学习,算法方面的东西。我是一个比较容易受我认为优秀的人影响的,我会去学习他的思维,他的做事风格。
C君则对大数据平台有推动的作用。当时公司还没有数据平台,C君推动公司购买了五台配置很低的服务器,直接放在了办公地点。然后我们一起搭建一个简单的Hadoop集群。
关于大数据平台,因为我经历过从无到有,到最后离不开它的整个过程,我形成了一套自己的观点。而这些观点,我放在了一次PPT分享里。这里可以提两点:
-
大数据平台(hadoop/spark),真的不要被‘大数据’这个词给吓到了。它大数据都可以处理,小数据当然是小菜一碟。本质上大数据平台是一种解决问题的范式,一个通用的分布式计算存储平台。想象一下,把一个文件丢进平台里,然后在Web上写个SQL就可以从各个维度分析这个文件里的数据了。整个过程可能只要花你几分钟,这比你花半天写个单机程序统计来的快吧。SQL一不小心写多了,设置成定时,就成BI报表了。
-
大数据平台搭建维护很贵吧?真不贵。大数据平台谁说了一定要大?一定要几百上千台机器了?没人说一定要这样子吧。我们当时5台机器,在百万数据集就能运行的很好了。什么样的数据量,使用什么规模的集群。当你的价值体现出来了,公司自然也会毫不犹豫的给你加机器了。
我们当时完成的第一个项目是EDM,邮件精准投递。当然这个项目的前提是需要对人有一个画像。于是我们几个人加上产品头脑风暴了好长一段时间,人工定义了上百个属性,加上一个由词构成的属性集合(14000维度),得到了对人的维度表征。邮件的话则直接使用14000维的词特征表示。
假设人的特征集合是A,邮件的特征集合是B,目标值为0或者1
- 0 表示不会打开邮件
-
1 表示会打开邮件
f(A,B) => 0|1
典型的一个二元分类或者逻辑回归问题。
做完后邮件打开率提升还是很显著的。当时我们想尽办法推测出用户的年龄,技能,职位等各种信息。有一些属性的预测取得了相当不错的效果,比如用户年龄,我们拿同事的账号进行年龄预测,上下浮动不超过2岁。
但做完这项目后C君,F君相继离开了,但这个是我数据道路上的一个开端。13年年中,来了K君。K君之前是某大型视频网站的数据部门负责人。应该说,通往数据道路康庄大道由此完全打开。此时公司战略上也开始支持数据部门,人员迅速扩充到15人左右,包括数据分析,开发,算法。不过实习生占了很大一部分,服务器方面,新采购的单台都至少24+核,32+G 内存。
13年到14年是一段非常辛苦的路。在这两年我实现了快速的成长,开始了大数据平台架构之路,同时也投入了相当一部分时间在机器学习和数据研究之上。
应该说,公司的数据平台是完全从0开始的,我和K君对整个平台做了比较详细的规划。
第一步推动公司进一步扩充了集群。我们也开始了自己的第一个目标,构建公司自己的BI系统。
K君亲自制定了数据上报格式规范。我则基于Hive使用其SerDer机制开发了一套数据格式解析器。支持通过JSon格式文本描述日志格式,然后自动映射到Hive表中。这样新来一个格式的数据,你只要填写一个json格式的描述文件,就能使用Hive直接进行SQL查询。
另外指导一个实习生开发了日志接受服务。同时L君则改写了阿里开源的一个宙斯平台。基于该平台,可以直接在Web界面管理和调试Hive/MapReduce任务,并且设置调度任务。
完成了这些工作,我们构建起了数据分析平台的雏形。在宙斯添加大量的SQL统计脚本,计算结果导入到MySQL中,然后在Web端展示,完成了BI报表的任务。当然这只是一个离线计算平台,真正和应用平台打通,形成完善的数据流入流出,需要做的工作还太多。
从那个时候起,一直到2014年11月,我们终于完整的构建了一个数据支撑平台。
-
Hadoop/Spark/HBase 体系,支撑BI,数据离线分析,推荐协同计算等
-
分布式索引服务,支撑搜索,数据平台供查询数据的存储
-
统一查询引擎,为数据产品提供统一的查询接口
-
内容网关+数据网关+上报,打通产品到数据平台的入口。
-
分布式缓存体系(Redis) ,可支持推荐系统,数据网关等产品
-
初步的服务监控体系 (参看: https://code.csdn.net/allwefantasy/platform 的介绍)
-
推荐系统,支持相关内容推荐,用户个性化推荐,公共队列展示,底层完全基于Redis实现。这里有个给兄弟公司介绍的一个PPT( http://vdisk.weibo.com/s/HZFjdG-haPc )
-
配置与发布系统(运维相关)
基本上在这个过程中是去数据库化的。HBase做数据存储,分布式索引服务则将数据进行索引,支撑复杂查询,统一查询引擎则以一致的接口对外提供查询服务。
关于这两年做的架构,我未来专门写了一篇文章进行解析。
平台是你顺利开张其他工作一个很重要的基础设施。当你有了一个完善,易于扩展的平台,你的工作会越来越少,新添加的东西会越来越轻量。你会发现,啊,原来这个都已经是被平台囊括了,啊,只是加个模块嵌入进去就完事了。
后续谈到的机器学习,很早之前其实我也接触过,搞个SVM lib弄弄,都是C的,单机的,生成个个是数据都费事,更别说后面的训练跑了。有了平台后,真的就看你的自己的聪明才智了,你更容易获得你想要的数据,你更方便将数据转化为你需要的格式,你更容易快速看到你的算法在实际数据集上的效果。
举个简单例子,我们做了一个智能问答的项目,在现有平台上做,只花了两天多时间。如果没有平台,我智能呵呵了,一个礼拜都不一定能做顺畅了。
北京的旅程-机器学习之路
2014年开始基于Yarn平台引入Spark。因为内部使用的是CDH4.4.0 版本的Yarn,Spark默认支持有点问题,所以必须自己下载源码,修改一些地方才能编译通过。Spark 平台是对数据分析师,算法工程师们的恩赐。我之前做一个数据调查,或者是为了产生一个训练文件给算法用,可是颇费周折。Hadoop的开发部署发展了这么多年,其实还都是挺麻烦的。用Spark几行代码就可以搞定,而且本地IDE写好,直接黏贴到spark-shell交互式运行。
对于算法工程师而言,原先比如使用贝叶斯之类的,测试只能跑个小数据集,不然很久都跑不完啊,跑一个礼拜没出结果也是常事。有了Spark之后,测试的时候就直接在一定规模的数据上跑了。真实的数据都在集群上,省去了要下载数据到本地的问题。要知道,目前大部分算法本质上是通过大量的数据通过一些优化算法提取出目标函数的参数,算法的这种形态决定过了只有在一定规模的结果集上才能如实得到实际数据集上的效果。而Spark则很好的满足了这种需求。
Scala 是我比较愿意接受的第三个语言。第一个是Java,从大学开始就一直用着,第二个是Ruby,有过一段短暂Rails程序员的经历,也从中得到很多灵感。现在的话,基本是Scala,Java混合编程。Scala 确实能够有效的提高编程效率,而且可以和Java无缝操作。在公司内部系统中,基本上都是混合着用的。
程序员再也不应该仅仅是写代码让服务跑起来或者设计一个架构做到良好的扩展性,这些工作本质上是重复性的工作,你很难做到和别人不一样,所以才会有码农,你只是垒代码。随着计算能力的提高,以及机器学习的发展,程序员的目标应该更加高尚,我怎么才能让你在茫茫人海中找到多看了你一眼的人?
前面我提到,在做架构的过程中,我对数据分析和机器学习也非常感兴趣,期间也做了一些成果。虽然主要精力还是在架构上,但经常会抽出时间做相关的研究。
新词发现是一个非常有意思的领域,用途非常多。譬如可以构建垂直领域词库,自动发现新热门词汇。词库的重要性我不用强调了。基于Spark强大的计算能力,我直接对200万+ 的博文进行了分析,得到大概八万词,包含 中文,英文,中英文混合词。通过凝固度,自由度,词频,idf,以及重合子串(比如 c1c2c3..cN c2c3..cN-1 这种形态的 我们认为是重合子串,如果词频一样,则都过滤掉,否则留词频高的)五个维度进行阈值设置和过滤。事实上,中间结果可以到几百亿,一个不小心就可以把Spark跑死,但是也在这个过程中慢慢对Spark有了更深的理解。 最终效果还是不错的,现在它已经作为我们的基础词库了。
算法自然是参考论文的,但我感触比较深的是,通常某篇论文只会在一个视角去focus 某件事情,所以你需要参考多篇,从不同角度去理解这件事情的解决方式,最后通过实验综合,得到一个更好解决方案。我参考了两篇论文,比如凝固度,自由度是出自一篇论文,而重合子串则来自另外一篇论文,然后自己观察实际数据,添加了很多规则,才得到最后的结果。
新词发现这个我足足做了两到三个礼拜,能有这么多时间focus在这件事情确实不容易。在公司,有太多的工作和新的想法需要去实施,尤其是公司在快速的转型或者上升期。我业余时间虽然不加班,但是我常常会在脑海里把系统架构方面的东西不断排练,就像大脑是个虚拟机,模拟器,一整套处理流程都会在大脑里事先跑起来,这对自己掌握某个系统,或者是对全局的掌控非常重要。
一说到算法,大概很多人心里就是想着,恩,我把数据转化为算法需要的格式,然后丢给现成的算法跑,跑着就出结果,或者出模型,然后反复尝试,直到得到你认为能接受的或者最优的结果。我一开始也是这么想的,可是如果你真的做这件事情,就发现完全不是那样子啊,需要注意的细节太多了。
新词发现没有现成的工具包,所以完全自己写了。第一步,你要获取语料。这容易,基于现有的平台,我从我们资源中心挑出了200万篇文章id,然后根据id到数据网关获取title,body字段。这个基于现有的平台,也就一个SQL + 几行Scala代码就搞定的事情。
SQL 其实就是用Hive 生成一个200万博文id列表。 Scala 代码看起来像这个样子
sc.textFile("/hdfs-upload-dir/20140904-114357-result.txt",30).flatMap{f=> val Array(id,name,skill) = f.split("\t") getFromUrl(id,"blog","title,body") }.filter(f=> f.length > 100 ).saveAsTextFile("/output/william/newwords/articles")
因为我们的新词发现是没有词典的,需要枚举所有组合,然后通过一定的规则判定这是不是一个词。比如 ‘我是天才’,就这四个字,组合有,‘我是’,‘我是天’,‘我是天才’,‘是天’,‘是天才’,‘天才’ 。你想想,200万篇文章,这种组合得多夸张,问题是你还要接着给这些组合做计算呢。这个算法可没告诉你怎么处理的,你只能自己去想办法。看到了,真正你做算法的过程中,不只是实现,你需要面对的问题特别多,我是怎么做的呢?
- 将所有html标签替换成空格,通过小空格切分后我们就能得到无数的小文本块,然后我们就能做词枚举了
- 一个词最长不能超过5个字
- 将中文,中英文,英文分开来做
- 将一些特殊字符 类似‘!¥……()+{}【】的呀啊阿哎吧和与兮呃呗咚咦喏啐喔唷嗬嗯嗳你们我他她这是由于’ 这些不可能成词的字符先去掉
这样,词集合就小多了。 接着就是按论文里的规则做计算了,比如算词的凝固度,算重合子串。这里面还会遇到很多性能,或者内存的坑,比如Spark里的groupByKey,reduceByKey。 我一开始省事,用了groupByKey,歇菜了,内存直接爆了,为啥,你要去研究groupByKey到底是怎么实现的,一个词出现几十万次,几百万次都很正常啊,groupByKey受不了这种情况。所以你得用reduceByKey。
很好,实现了算法后得到了结果,可人家没告诉你,他贴出来的结果都是好看的,那是因为他是按频次排的,但如果你拉到最后看,结果就不太好看了。这个时候你就需要观察数据了,然后提出新的规则,比如最后得到的中文词结果,我用了下面的规则过滤了下
f._1.contains("和")|| f._1.contains("或")|| f._1.contains("就")|| f._1.contains("将")|| f._1.contains("是")|| f._1.contains("的")|| f._1.contains("为")|| f._1.contains("个")|| f._1.contains("到")|| f._1.contains("来")|| f._1.contains("种")|| f._1.contains("中")|| f._1.contains("length")|| f._1.contains("tmp")|| f._1.contains("void")|| f._1.contains("如")|| f._1.endsWith(":")|| f._1.endsWith("amp")|| f._1.endsWith("[")|| f._1.endsWith("]")|| f._1.endsWith("’")|| f._1.split("\\s+")(0) == "if" || f._1.split("\\s+")(0) == "for"||
上面的规则是什么意思呢?凡是词里面包含‘或’的,或者'就'的或者上面罗列的,我都认为这个词是没有意义的,经过这个简单规则一过滤,效果好非常多,很多没什么意义的生活词,或者不成词的词就被去掉了。中文,英文,中英文混合,我都加了很多这种规则,最终才过滤出了八万计算机词汇。
在多分类的算法中,贝叶斯和SVM的效果是相当不错的,Spark中朴素贝叶斯的实现基于该论文: http://t.cn/RPkPkJq ,我看了一遍,在我的数据集上跑的效果并不好。我修改了论文中 p(t|c) 的公式 为 p(t|c) = 出现t的c分类下的文章数/c分类下得所有文章数 对于t|d=0的情况不参与计算。然后舍弃采用Log将乘除转化为加减。分类效果得到明显提高。
我把它应用在了代码篇的语言判断上。给我一段代码,我告诉你这是什么语言写的。一开始识别率就达到70%左右,后面通过提高维度,将代码片高维表示后(65万),准确率提升到了85%。总体而言,贝叶斯和SVM后面有人提出了各种改良,但是最后是改良了还是改差了,还得看具体数据,你需要有调整他们的能力。
再说一个应该说非常具有实际意义的一个算法:职位和简历匹配度算法。当然设计的是为了招聘研发,所以基调就是以技能模型为主,提出一套完整匹配度算法。效果不错。之后的研究人员基于我的算法,添加了职位方向等因子,使得效果更进一步。这套系统会成为后续招聘领域比较重要的基础。
人生第一次跳槽
在上一家公司工作了五年之后,我终于跳槽了。当时老板(我们老板是一个非常优秀的老板)请我吃饭的时候,问我为啥跳槽,我说我想开始做些事业。我能呆一家公司呆五年,说明老东家是真好。
我到了L公司之后,初期主要是实时计算这块。实时计算能做的事情还是非常多的。这让我后续以Spark Streaming 为起点,深入研究Spark 内部源码做好了铺垫。
此时我除了负责一个应用开发团队,同时还负责内部的机器学习团队。然而我是一个很懒的人,不太适合带团队,我觉得我需要太多的时间投入到技术上去,去专研。所以团队发展不足,这也让自己很愧疚。然而只要和我工作过的人,我一定会让他们有技术上的收获。和我一起共事的同事有的去了百度,有的去了滴滴,大部分都还在互联网公司。有一次吃饭的时候,他们有人说,虽然我很严苛,但是确实给他带来了收获。听到这一点,我还是很开心的。技术人员应该以技术为纽带,互相帮助对方去提升。
Spark 的再相会
经过八个月业余时间(周末加上工作日夜晚)的努力,我想要的产品原型终于做成了。然而终究是计划有调整,在主动和一些CTO,资深技术人员,一些已经创业成功的人聊,加上碰了一些壁之后,我打算放慢些节奏。似乎光有个原型是不足以打动投资人的。
这个时候,Spark 对我的吸引力突然无限超越了事业对我的吸引力,所以三个月时间我写了 20几篇Spark相关的文章 ,并且推动部门上了很多Spark Streaming相关的应用。
在此期间,我大量阅读源码,并且修正了不少在特地情况下Spark会工作不正常的错误,同时做了一些增强。这些工作在 Spark Streaming 的玫瑰与刺 以及 Spark 动态资源分配(Dynamic Resource Allocation) 解析 有所提及。
技术的轮回
最近基于Spark Streaming + ElasticSearch 做数据的日志分析。还记得我12年(也可能是11年)引入ES做搜索,那个时候简直被虐死,所以开发了一套自己的索引系统。没想到四年后又遇到它了,而这个时候不在是在搜索领域,而是在大数据日志分析领域。人和技术,都存在某种轮回。
</div>