這些年,我工作上走過的路

常常的,我會感恩于我所在的公司,讓自己經(jīng)歷了種種。很多情況下,公司的成長帶動了自己的成長。完整的跟著公司經(jīng)歷大數(shù)據(jù)業(yè)務(wù)從無到有,從有到精,這種歷程就像美味的食物,吃過了才能真正感覺,而文字是不足以表達的。

我走過了畢業(yè)季,創(chuàng)業(yè)征途,踏進開源之路,轉(zhuǎn)型進入大數(shù)據(jù),到最后有緣接觸機器學習。每個章節(jié),我都會提及對應(yīng)那個階段對技術(shù)的感悟,自己做的一些具體事情。

到寫這篇文章為止,我發(fā)現(xiàn)經(jīng)過這八年,我依然沒有懈怠下來,我依然在狂奔。

畢業(yè)季

2008年12月,清晨的陽光有氣無力的鋪在了一片沒有經(jīng)過打理的草地上。有了陽光,沒了打理,自然成了雜草兒們的天堂,千奇百怪任性長著。陽光順著草地,扶著墻翻過窗子,躍進了陽臺。陽臺左邊是洗手間,前方是一個虛掩著的門,到了這,陽光止住了它慵懶的腳步。大學的宿舍是長方形的,四個邊角都放著寫字臺和床。說是床,其實就是寫字臺上的一個擋板。海南蚊子多,所以擋板上都是有蚊帳的,蚊帳帶來的壞處是,如果蚊子進去了,它除了煩你也別無出路,好處是,可以形成自己的一個小牢籠。我睡眼惺收,散發(fā)著一絲頹廢的氣質(zhì)。頹廢在這是一種贊美的詞,只有藝術(shù)家才能配的上頹廢這個詞。當然,我不是藝術(shù)家,所以放在我身上,也就是真實頹廢本意解釋了。很快,我會熱血的成為幾百萬即將畢業(yè)的學生,被學校撒豆成兵,最后可能成為炮灰。

我確實成為了炮灰。

剛從深圳鎩羽而歸,原本希望能在深圳找份工作,但落了空,完全沒有門道,愣頭愣腦的去了,愣頭愣腦的回來。期間十幾天,一個面試的機會都沒有撈到,深圳現(xiàn)在也是完全不記得什么樣子了。

這種感覺,想必和艾倫第一次去和巨人戰(zhàn)斗的情景是一樣的。

框框框,有人敲門,我們沒搭理,接著他在門外問:有個公司來學院招聘,是招計算機的,你們要不要去看下。

我餓了,真的餓了,我沒做任何思考,便起床動身。原先困倦的大腦腦功率趨近于0,現(xiàn)在瞬間飆升。恩,是腦功率,不是荷爾蒙。

那個時候自己就像一只農(nóng)村的土狗,只要有份工作就行。而且如果純粹做個碼農(nóng),我還是很自信的。大學期間我就已經(jīng)定了方向,專攻Java,所以或多或少還是有些積累,畢設(shè)的時候用Java寫了個程序,給磁盤建索引,用的Lucene,順利過了畢設(shè)。沒想到的是,我竟然因此和搜索結(jié)緣,一直持續(xù)到今天。

創(chuàng)業(yè)征途

突然來的機遇就是這么神奇,也讓人感覺莫名其妙,說來就來了,你真的不知道為什么會來,但真的就是這么來了。

當機遇來臨的時候,常常讓人懊悔的是抓不住。但抓住了,也未必會讓你成功。但是,這是一個不管成功或者失敗,都讓你收獲滿滿的一次機遇。

這是一家創(chuàng)業(yè)公司。我去的時候一開始只有三個人,A君,B君,還有我。

A君多才多藝,產(chǎn)品經(jīng)理+UI設(shè)計+投資人,B君和我則同為技術(shù)合伙人。

在找到我之前,A君和B君已經(jīng)在海南師范大學旁邊的一棟寫字樓租了一個辦公室?,F(xiàn)在回想一下,或許我們應(yīng)該租個地下室,成功的概率可能會更高些(不過,如果去美國的車庫或者地下室,應(yīng)該成功率又會提高)

就這樣,08年12月開始了我程序員,或者是創(chuàng)業(yè)的征程吧。

我們做的是一個原創(chuàng)音樂站點。

這期間我們常常每天工作13-14小時。要知道,那個時候我們沒做過任何項目啊,只是大學看了幾本程序設(shè)計的書,而真正做出一個產(chǎn)品,需要掌握的東西卻是是非常多的。

但是熱血和時間這東西,真的是有用的。就這么著,基于熱血的推動,時間的磨礪,漸漸的,一個原創(chuàng)音樂分享網(wǎng)站竟然慢慢開始開始有模有樣了,整個過程,我們自己設(shè)計,開發(fā),購買服務(wù)器,托管,運維,運營。

作為一個流媒體音樂站,不同于一個簡單博客,尤其是對于我們幾個沒有什么技術(shù)積累的年輕人而言,其挑戰(zhàn)是非常大的。

流媒體服務(wù)器,Web端Mp3播放器,音樂上傳,音樂轉(zhuǎn)碼,音樂下載,個性化主頁等等,挑戰(zhàn)非常多。B君后期專攻頁面和JS,我想,他現(xiàn)在能夠開發(fā)Web端操作系統(tǒng),也得益于這次的挑戰(zhàn)的吧。

首先是站點搭建,沒有采用Worldpress之類的開源組件,真的是從零直接從頭開始做的。那個時候不知道原型設(shè)計工具Axure,A君就直接用Photoshop把界面畫出來,然后把一些小ico切出來給我們用。A君雖然沒有做過產(chǎn)品經(jīng)理和UI設(shè)計師,但是他設(shè)計出來的界面真心大氣(08年的時候),后續(xù)我們的對手,原創(chuàng)音樂中國,還有那有個因為涉黃被關(guān)閉的一個網(wǎng)站,都在我們上線后不久改版,我們對比過,明顯借鑒了我們的設(shè)計元素。

我和B君大學學的都是Java,于是采用了SSH2開發(fā)。從頭開始壘代碼。還是那句話,如果只是做個類似博客平臺的站點自然是不難,但我們做的是原創(chuàng)音樂分享網(wǎng)站。這里面涉及到如下幾個難點:

  1. 首先我們是個音頻流媒體網(wǎng)站,需要搭建流媒體服務(wù)器,以及播放音頻的客戶端

  2. 接著這是針對音樂人的一個社交網(wǎng)站,有點類似現(xiàn)在的微博,音樂人上傳了大量自己的音頻,需要大量的粉絲以及與之互動。所以需要提供一個酷炫的個人主頁,QQ空間是一個標桿。

于是經(jīng)過仔細研究,我們使用了Red5 搭建了音頻流媒體服務(wù)器,實現(xiàn)了一個簡易的 flash 音頻播放器,暴露js調(diào)用接口,使用Js進行控制。

個人主頁我們花費的精力非常多,09年時,我們就已經(jīng)仿照QQ了,允許換膚,自定義布局,這個對前端以及后端要求都挺高的。后面B君在做后端服務(wù)的時候,也同時成了一個前端高手,我可以說,他已經(jīng)精通CSS和JavaScript了。(后來B君來了北京,后續(xù)又去了香港,在香港時,已經(jīng)可以用JS開發(fā)Web操作系統(tǒng)了,這是后話)。 整個頁面任何一個版塊,你都可以顯示,隱藏,互換位置,設(shè)置不同模板。

作為一個流媒體網(wǎng)站,上傳音頻是個很重要的東西,為了顯示上傳進度,我們當時就折騰了好一會,接著遇到轉(zhuǎn)碼問題,使用了ffmpeg,設(shè)置要把轉(zhuǎn)碼進度也顯示給用戶看。

到后來,我們已經(jīng)做了一個類似蝦米這種音樂類的網(wǎng)站很多功能了,比如給出音樂列表,自動播放,直接在title上顯示播放進度等等。

SSH2 給我的感覺就是慢,調(diào)用棧太深了。作為一個互聯(lián)網(wǎng)應(yīng)用來說,真的不適合。但是架構(gòu)已經(jīng)選定,也沒辦法。于是我們通過大量添加緩存的方式解決性能問題。

有大量的資源,自然就需要搜索了。為了方便查找歌曲,我們引入了基于Lucene的Compass??梢灾苯踊跀?shù)據(jù)庫建立lucene的索引文件。一般這種東西,很難用好,或多或少都有問題。我期間就經(jīng)常各種錯誤,各種問題,不堪其擾。

到10年的時候,我們的歌手用戶只有幾千。但是歌曲數(shù)量以及總文件大小已經(jīng)相當可觀了。我們在各個細節(jié)進行了非常大的努力,比如歌曲,用戶評論,可見不可見,上傳進度,頁面設(shè)計等等。

產(chǎn)品我們覺得問題不大了,可是,可是我們該怎么推廣運營呢?完全沒有門道。而且從08年到10年,差不多一年半,我們是完全沒有盈利的,只是在燒A君的錢。

如果有了一定的用戶量和活躍度,其實關(guān)于盈利的形態(tài)我們都是想好了的,當然這個也是借鑒國外的模式。而且我到現(xiàn)在都認為是一個好的模式。

但是我們感覺我們快撐不到那個時候了。我們那時候也沒有投資人的概念。在海口,互聯(lián)網(wǎng)行業(yè)是相當不發(fā)達的。不像現(xiàn)在,你拿個想法,跑到咖啡廳,就有人會聽你講。

于是我們展開了自救行動。10年團購很火,于是,我們打算先暫時放下手中的主業(yè),做起了團購。但是后面我們才知道,團購初期是很燒錢的,不是我們能玩的起的。

海南是個旅游大省,于是我們開始做旅游站,但是啊,旅游要有線下資源。

急了就什么都嘗試了。

2010年10月國慶期間,基本上宣告了創(chuàng)業(yè)的失敗。??谟袀€奇特的天文現(xiàn)象,就是凡是國慶七天,那是必然下雨的。這個國慶也不例外,整整七天都是雨。我當時是個E站的一個老用戶(只是看文章的老用戶),看到了E站正好招人,但那個時候招的是Ruby程序員。于是十一前的一個禮拜,我弄了一本敏捷開發(fā)的書,然后把58同城的UI扒下來,然后用ruby on rails 寫了站點,包括抓取,包括顯示等。當然,沒有后臺。整整做了一個禮拜,然后把它作為示例代碼打包,發(fā)給了E站。 后面就接到了E站老大的面試電話。

E站的老大看了我的代碼后,讓我很順利通過了電面,問我是否可以直接去北京。我當時心想,偶像就是偶像,看代碼就能看到我的能力以及誠意,沒有N輪面試的折騰。

走的那天,好像還是下著雨。當時我的生活已經(jīng)非常窘迫了,一個好朋友贊助了我機票錢,我也在沒有找到北京住處的情況下,就踏上了北京的航班(臨走的那天,B君說他也在北京,可以給我落腳,當時那個感動),開始了我現(xiàn)在的工作。

北京的旅程-開源之路

起源

2010年10月15日,我正式在C公司入職。E站是C公司的一個子站點,用RubyOnRails 開發(fā)的。我一開始基于其上做開發(fā)。就這么做了一個月Ruby程序員,有一個事情就第一次改變了我的職業(yè)方向。

某天老大突然說,你不是以前用Java做過搜索么,公司主站點的搜索就交由你做吧。當時公司的搜索是外包給一家專門的公司做的。我自然很樂意的接受了。

后面經(jīng)過一個月的開發(fā),也就是2010年12月中旬時候,第一個版本上線了。當然這個版本可以說超級簡單,就是用Lucene搭建了一個單機版本的搜索服務(wù)。老大很開心,還請我們?nèi)タ戳俗屪訌楋w。

Web/ORM/ODM 一站式開發(fā)框架

因為我之前做過一段時間的Ruby程序員,一對比,我發(fā)現(xiàn),Java的Web框架都太不好用了,Java的ORM框架也不好用,Java 的MongoDB Client 也不好用。于是我決定開發(fā)一套一站式Web框架。

正好除了搜索的任務(wù)以外,公司希望做一個全站通用的標簽系統(tǒng)。當時在選型上,老大說用Spring,我當時說,給我點時間,我自己開發(fā)一套開發(fā)框架出來,老大說,你有信心做好么,我說有。老大給予了肯定的答案。

于是,2011年的有一段時間,每天早上六點我準時起來,光著膀子開始寫代碼(這個可以推測是夏天了)。寫了一個Web框架,一個ORM框架,一個MongoDB的 ODM。 后面我問老大,名字叫什么好,老大說,就叫ServiceFramework。于是我便把Web框架叫做 ServiceFramework,ORM框架叫做 ActiveORM,MongoDB的 ODM叫MongoMongo。經(jīng)過公司許可開源了出去。

相關(guān)介紹參考:

http://allwefantasy.iteye.com/blog/1631522

http://www.iteye.com/news/25793

項目地址:https://github.com/allwefantasy/ServiceFramework

從2011年開始,我一直在優(yōu)化這個項目,到現(xiàn)在已經(jīng)四年了。不過開源版本因為工作緣故,一直沒有更多精力維護,并且無法進行推廣。但是內(nèi)部版本卻獲得長了長足的發(fā)展,作為一個針對API服務(wù)開發(fā)的框架,除了易用性以外,我一直重點做的是可運維。目前我所在的數(shù)據(jù)部門,已經(jīng)完全使用了這套框架。

關(guān)于可運維,框架自身可以做到的:

  • 接口 QPS 監(jiān)控
  • 接口平均響應(yīng)耗時監(jiān)控
  • 接口調(diào)用量(如果是http的話,則是各種狀態(tài)碼統(tǒng)計)
  • 內(nèi)置HTTP接口,外部可通過該接口獲取以上的數(shù)據(jù)

同時,框架日志信息輸出默認包括:

  • http請求url
  • 整個請求耗時
  • 數(shù)據(jù)庫耗時(如果有)
  • 響應(yīng)狀態(tài)碼

還有一個比較核心的功能是,服務(wù)降級限流。
ServiceFramework主要面向后端服務(wù),如果沒有自我保護機制,系統(tǒng)很容易過載而不可用。經(jīng)過一定的容量規(guī)劃,或者通過對接口調(diào)用平均響應(yīng)耗時的監(jiān)控, 我們可以動態(tài)調(diào)整 ServiceFramework 的QPS限制,從而達到保護系統(tǒng)的目的。

這里其實還有一個重點是,傳統(tǒng)的方式是,容器包含應(yīng)用,比如開發(fā)好的代碼打成war包放到tomcat等容器中。新框架的方式是應(yīng)用包含容器(內(nèi)嵌jetty),一個應(yīng)用服務(wù)就是一個純粹的java application.

開發(fā)完這個框架后,我花了半個月時間完成了公司標簽系統(tǒng)的開發(fā)。

索引系統(tǒng) (暫時未開源)

當時老大看上了一個叫ElasticSearch的搜索項目,類似Solr。不過那個時候ES還非常的初級,我當時年少氣盛,沒經(jīng)過任何測試就上線了,但是對其了解有限,上線后問題不斷,當時索引量已經(jīng)頗大,光索引文件就達到百G。一開始我將原始數(shù)據(jù)也store進了索引,瞬間IO飆升,服務(wù)直接掛掉了。接著我講原始文件剝離,只存儲索引文件,但是發(fā)現(xiàn)也扛不住,服務(wù)經(jīng)常因為壓力大而沒有響應(yīng),因為ES有Failover功能,如果發(fā)現(xiàn)有服務(wù)當?shù)袅?,就進行分片副本遷移,直接把網(wǎng)絡(luò)帶寬占滿(那個時候路由器都是百M的)。我就開始看代碼,改代碼,但是不得要領(lǐng)。當時ES的社區(qū)遠不如現(xiàn)在活躍和成熟。

我后悔了,不應(yīng)該沒有調(diào)研測試清楚就上線。而且當時一直困擾我的就是數(shù)據(jù)更新問題。索引了后,數(shù)據(jù)很快變更,我這邊必須想辦法得到通知。

于是我決定另起爐灶,開發(fā)一個簡化版本的ES,使其完全能被自己掌控。經(jīng)過一個月的開發(fā),第一個版本的我們稱之為CS的項目完成了。后面使用CS替換掉了ES。服務(wù)再也不會輕易當?shù)袅恕?/p>

在一次ES的分享會上,我分享了CS。蠻多人還是感興趣的。
CS作為一個分布式索引服務(wù),特點有:

  • 分布式架構(gòu)
  • 支持索引數(shù)據(jù)分片
  • 支持構(gòu)建離線全量索引過程中合并線上新增數(shù)據(jù)的機制
  • 支持數(shù)據(jù)熱備
  • 擁有一個剝離配套的統(tǒng)一查詢引擎
  • 支持模塊化,組件化

關(guān)于這個項目的一些簡單介紹,可參看:

http://pan.baidu.com/s/1i3qsoBF#path=%252FESCC%25233&render-type=list-view

中的 ES分享.pptx 文件

CS的核心是是查詢引擎和索引存儲剝離。一些高級功能,比如跨索引檢索,結(jié)果二次排序,摘要提取,獲取詳細內(nèi)容展示,都是作為模塊放在查詢引擎中。當然統(tǒng)一查詢引擎最核心的意義還是在于可以快速更新二次排序的引擎。當然這還需要有一些其他架構(gòu)做支撐。

有新的模塊添加,只需重啟查詢引擎,而不需要重啟索引存儲服務(wù)。索引文件重新打開是非常消耗CPU,IO的,常常會造成機器負載瞬間飆升,導致很多搜索維護人員輕易不敢重啟服務(wù)。在CS不存在這個問題。

12年的時候,我終于有伙伴了,以前一直都是一個人孤軍奮戰(zhàn)。我稱為C君。C君后來參與搜索的優(yōu)化。之前我因為對Lucene的一個誤解,導致排序效果一直很爛,我一直不得要領(lǐng)。C君發(fā)現(xiàn)了這個問題,瞬間搜索排序就正常了。后來C君開發(fā)了一套新的分詞引擎,現(xiàn)在已經(jīng)是一個知名的分詞套件了(可參考:https://github.com/NLPchina/ansj_seg)?;谶@套分詞引擎我們做了很多分析方面的工作。

索引服務(wù)這個項目前前后后花了我四年多的時間?,F(xiàn)在策略層公用的組件已經(jīng)包括 SQL,JSON,URL params,Mutil-Index,數(shù)據(jù)網(wǎng)關(guān)等。后面我一直從事數(shù)據(jù)架構(gòu)和算法方面的專研時,索引服務(wù)也成為架構(gòu)中非常核心的一個服務(wù)。

北京的旅程-大數(shù)據(jù)架構(gòu)之路

到12年年末為止,應(yīng)該說我做的大部分是項目層級的工作。13年年初,公司突然開始重視大數(shù)據(jù)了。于是我們部門人員由原來的兩個人變成了五個人。加了兩個剛畢業(yè)的學生D君和E君以及一個算法工程師F君。

F君也是對我影響很大的一個人,讓我從此了解了機器學習,算法方面的東西。我是一個比較容易受我認為優(yōu)秀的人影響的,我會去學習他的思維,他的做事風格。

C君則對大數(shù)據(jù)平臺有推動的作用。當時公司還沒有數(shù)據(jù)平臺,C君推動公司購買了五臺配置很低的服務(wù)器,直接放在了辦公地點。然后我們一起搭建一個簡單的Hadoop集群。

關(guān)于大數(shù)據(jù)平臺,因為我經(jīng)歷過從無到有,到最后離不開它的整個過程,我形成了一套自己的觀點。而這些觀點,我放在了一次PPT分享里。這里可以提兩點:

  1. 大數(shù)據(jù)平臺(hadoop/spark),真的不要被‘大數(shù)據(jù)’這個詞給嚇到了。它大數(shù)據(jù)都可以處理,小數(shù)據(jù)當然是小菜一碟。本質(zhì)上大數(shù)據(jù)平臺是一種解決問題的范式,一個通用的分布式計算存儲平臺。想象一下,把一個文件丟進平臺里,然后在Web上寫個SQL就可以從各個維度分析這個文件里的數(shù)據(jù)了。整個過程可能只要花你幾分鐘,這比你花半天寫個單機程序統(tǒng)計來的快吧。SQL一不小心寫多了,設(shè)置成定時,就成BI報表了。

  2. 大數(shù)據(jù)平臺搭建維護很貴吧?真不貴。大數(shù)據(jù)平臺誰說了一定要大?一定要幾百上千臺機器了?沒人說一定要這樣子吧。我們當時5臺機器,在百萬數(shù)據(jù)集就能運行的很好了。什么樣的數(shù)據(jù)量,使用什么規(guī)模的集群。當你的價值體現(xiàn)出來了,公司自然也會毫不猶豫的給你加機器了。

我們當時完成的第一個項目是EDM,郵件精準投遞。當然這個項目的前提是需要對人有一個畫像。于是我們幾個人加上產(chǎn)品頭腦風暴了好長一段時間,人工定義了上百個屬性,加上一個由詞構(gòu)成的屬性集合(14000維度),得到了對人的維度表征。郵件的話則直接使用14000維的詞特征表示。

假設(shè)人的特征集合是A,郵件的特征集合是B,目標值為0或者1

  • 0 表示不會打開郵件

  • 1 表示會打開郵件

    f(A,B) => 0|1

典型的一個二元分類或者邏輯回歸問題。

做完后郵件打開率提升還是很顯著的。當時我們想盡辦法推測出用戶的年齡,技能,職位等各種信息。有一些屬性的預(yù)測取得了相當不錯的效果,比如用戶年齡,我們拿同事的賬號進行年齡預(yù)測,上下浮動不超過2歲。

但做完這項目后C君,F君相繼離開了,但這個是我數(shù)據(jù)道路上的一個開端。13年年中,來了K君。K君之前是某大型視頻網(wǎng)站的數(shù)據(jù)部門負責人。應(yīng)該說,通往數(shù)據(jù)道路康莊大道由此完全打開。此時公司戰(zhàn)略上也開始支持數(shù)據(jù)部門,人員迅速擴充到15人左右,包括數(shù)據(jù)分析,開發(fā),算法。不過實習生占了很大一部分,服務(wù)器方面,新采購的單臺都至少24+核,32+G 內(nèi)存。

13年到14年是一段非常辛苦的路。在這兩年我實現(xiàn)了快速的成長,開始了大數(shù)據(jù)平臺架構(gòu)之路,同時也投入了相當一部分時間在機器學習和數(shù)據(jù)研究之上。

應(yīng)該說,公司的數(shù)據(jù)平臺是完全從0開始的,我和K君對整個平臺做了比較詳細的規(guī)劃。

第一步推動公司進一步擴充了集群。我們也開始了自己的第一個目標,構(gòu)建公司自己的BI系統(tǒng)。

K君親自制定了數(shù)據(jù)上報格式規(guī)范。我則基于Hive使用其SerDer機制開發(fā)了一套數(shù)據(jù)格式解析器。支持通過JSon格式文本描述日志格式,然后自動映射到Hive表中。這樣新來一個格式的數(shù)據(jù),你只要填寫一個json格式的描述文件,就能使用Hive直接進行SQL查詢。

另外指導一個實習生開發(fā)了日志接受服務(wù)。同時L君則改寫了阿里開源的一個宙斯平臺。基于該平臺,可以直接在Web界面管理和調(diào)試Hive/MapReduce任務(wù),并且設(shè)置調(diào)度任務(wù)。

完成了這些工作,我們構(gòu)建起了數(shù)據(jù)分析平臺的雛形。在宙斯添加大量的SQL統(tǒng)計腳本,計算結(jié)果導入到MySQL中,然后在Web端展示,完成了BI報表的任務(wù)。當然這只是一個離線計算平臺,真正和應(yīng)用平臺打通,形成完善的數(shù)據(jù)流入流出,需要做的工作還太多。

從那個時候起,一直到2014年11月,我們終于完整的構(gòu)建了一個數(shù)據(jù)支撐平臺。

  1. Hadoop/Spark/HBase 體系,支撐BI,數(shù)據(jù)離線分析,推薦協(xié)同計算等

  2. 分布式索引服務(wù),支撐搜索,數(shù)據(jù)平臺供查詢數(shù)據(jù)的存儲

  3. 統(tǒng)一查詢引擎,為數(shù)據(jù)產(chǎn)品提供統(tǒng)一的查詢接口

  4. 內(nèi)容網(wǎng)關(guān)+數(shù)據(jù)網(wǎng)關(guān)+上報,打通產(chǎn)品到數(shù)據(jù)平臺的入口。

  5. 分布式緩存體系(Redis) ,可支持推薦系統(tǒng),數(shù)據(jù)網(wǎng)關(guān)等產(chǎn)品

  6. 初步的服務(wù)監(jiān)控體系 (參看:https://code.csdn.net/allwefantasy/platform 的介紹)

  7. 推薦系統(tǒng),支持相關(guān)內(nèi)容推薦,用戶個性化推薦,公共隊列展示,底層完全基于Redis實現(xiàn)。這里有個給兄弟公司介紹的一個PPT(http://vdisk.weibo.com/s/HZFjdG-haPc)

  8. 配置與發(fā)布系統(tǒng)(運維相關(guān))

基本上在這個過程中是去數(shù)據(jù)庫化的。HBase做數(shù)據(jù)存儲,分布式索引服務(wù)則將數(shù)據(jù)進行索引,支撐復雜查詢,統(tǒng)一查詢引擎則以一致的接口對外提供查詢服務(wù)。

關(guān)于這兩年做的架構(gòu),我未來專門寫了一篇文章進行解析。

平臺是你順利開張其他工作一個很重要的基礎(chǔ)設(shè)施。當你有了一個完善,易于擴展的平臺,你的工作會越來越少,新添加的東西會越來越輕量。你會發(fā)現(xiàn),啊,原來這個都已經(jīng)是被平臺囊括了,啊,只是加個模塊嵌入進去就完事了。

后續(xù)談到的機器學習,很早之前其實我也接觸過,搞個SVM lib弄弄,都是C的,單機的,生成個個是數(shù)據(jù)都費事,更別說后面的訓練跑了。有了平臺后,真的就看你的自己的聰明才智了,你更容易獲得你想要的數(shù)據(jù),你更方便將數(shù)據(jù)轉(zhuǎn)化為你需要的格式,你更容易快速看到你的算法在實際數(shù)據(jù)集上的效果。

舉個簡單例子,我們做了一個智能問答的項目,在現(xiàn)有平臺上做,只花了兩天多時間。如果沒有平臺,我智能呵呵了,一個禮拜都不一定能做順暢了。

北京的旅程-機器學習之路

2014年開始基于Yarn平臺引入Spark。因為內(nèi)部使用的是CDH4.4.0 版本的Yarn,Spark默認支持有點問題,所以必須自己下載源碼,修改一些地方才能編譯通過。Spark 平臺是對數(shù)據(jù)分析師,算法工程師們的恩賜。我之前做一個數(shù)據(jù)調(diào)查,或者是為了產(chǎn)生一個訓練文件給算法用,可是頗費周折。Hadoop的開發(fā)部署發(fā)展了這么多年,其實還都是挺麻煩的。用Spark幾行代碼就可以搞定,而且本地IDE寫好,直接黏貼到spark-shell交互式運行。

對于算法工程師而言,原先比如使用貝葉斯之類的,測試只能跑個小數(shù)據(jù)集,不然很久都跑不完啊,跑一個禮拜沒出結(jié)果也是常事。有了Spark之后,測試的時候就直接在一定規(guī)模的數(shù)據(jù)上跑了。真實的數(shù)據(jù)都在集群上,省去了要下載數(shù)據(jù)到本地的問題。要知道,目前大部分算法本質(zhì)上是通過大量的數(shù)據(jù)通過一些優(yōu)化算法提取出目標函數(shù)的參數(shù),算法的這種形態(tài)決定過了只有在一定規(guī)模的結(jié)果集上才能如實得到實際數(shù)據(jù)集上的效果。而Spark則很好的滿足了這種需求。

Scala 是我比較愿意接受的第三個語言。第一個是Java,從大學開始就一直用著,第二個是Ruby,有過一段短暫Rails程序員的經(jīng)歷,也從中得到很多靈感。現(xiàn)在的話,基本是Scala,Java混合編程。Scala 確實能夠有效的提高編程效率,而且可以和Java無縫操作。在公司內(nèi)部系統(tǒng)中,基本上都是混合著用的。

程序員再也不應(yīng)該僅僅是寫代碼讓服務(wù)跑起來或者設(shè)計一個架構(gòu)做到良好的擴展性,這些工作本質(zhì)上是重復性的工作,你很難做到和別人不一樣,所以才會有碼農(nóng),你只是壘代碼。隨著計算能力的提高,以及機器學習的發(fā)展,程序員的目標應(yīng)該更加高尚,我怎么才能讓你在茫茫人海中找到多看了你一眼的人?

前面我提到,在做架構(gòu)的過程中,我對數(shù)據(jù)分析和機器學習也非常感興趣,期間也做了一些成果。雖然主要精力還是在架構(gòu)上,但經(jīng)常會抽出時間做相關(guān)的研究。

新詞發(fā)現(xiàn)是一個非常有意思的領(lǐng)域,用途非常多。譬如可以構(gòu)建垂直領(lǐng)域詞庫,自動發(fā)現(xiàn)新熱門詞匯。詞庫的重要性我不用強調(diào)了?;赟park強大的計算能力,我直接對200萬+ 的博文進行了分析,得到大概八萬詞,包含 中文,英文,中英文混合詞。通過凝固度,自由度,詞頻,idf,以及重合子串(比如 c1c2c3..cN c2c3..cN-1 這種形態(tài)的 我們認為是重合子串,如果詞頻一樣,則都過濾掉,否則留詞頻高的)五個維度進行閾值設(shè)置和過濾。事實上,中間結(jié)果可以到幾百億,一個不小心就可以把Spark跑死,但是也在這個過程中慢慢對Spark有了更深的理解。 最終效果還是不錯的,現(xiàn)在它已經(jīng)作為我們的基礎(chǔ)詞庫了。

算法自然是參考論文的,但我感觸比較深的是,通常某篇論文只會在一個視角去focus 某件事情,所以你需要參考多篇,從不同角度去理解這件事情的解決方式,最后通過實驗綜合,得到一個更好解決方案。我參考了兩篇論文,比如凝固度,自由度是出自一篇論文,而重合子串則來自另外一篇論文,然后自己觀察實際數(shù)據(jù),添加了很多規(guī)則,才得到最后的結(jié)果。

新詞發(fā)現(xiàn)這個我足足做了兩到三個禮拜,能有這么多時間focus在這件事情確實不容易。在公司,有太多的工作和新的想法需要去實施,尤其是公司在快速的轉(zhuǎn)型或者上升期。我業(yè)余時間雖然不加班,但是我常常會在腦海里把系統(tǒng)架構(gòu)方面的東西不斷排練,就像大腦是個虛擬機,模擬器,一整套處理流程都會在大腦里事先跑起來,這對自己掌握某個系統(tǒng),或者是對全局的掌控非常重要。

一說到算法,大概很多人心里就是想著,恩,我把數(shù)據(jù)轉(zhuǎn)化為算法需要的格式,然后丟給現(xiàn)成的算法跑,跑著就出結(jié)果,或者出模型,然后反復嘗試,直到得到你認為能接受的或者最優(yōu)的結(jié)果。我一開始也是這么想的,可是如果你真的做這件事情,就發(fā)現(xiàn)完全不是那樣子啊,需要注意的細節(jié)太多了。

新詞發(fā)現(xiàn)沒有現(xiàn)成的工具包,所以完全自己寫了。第一步,你要獲取語料。這容易,基于現(xiàn)有的平臺,我從我們資源中心挑出了200萬篇文章id,然后根據(jù)id到數(shù)據(jù)網(wǎng)關(guān)獲取title,body字段。這個基于現(xiàn)有的平臺,也就一個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")

因為我們的新詞發(fā)現(xiàn)是沒有詞典的,需要枚舉所有組合,然后通過一定的規(guī)則判定這是不是一個詞。比如 ‘我是天才’,就這四個字,
組合有,‘我是’,‘我是天’,‘我是天才’,‘是天’,‘是天才’,‘天才’ 。你想想,200萬篇文章,這種組合得多夸張,問題是你還要接著給這些組合做計算呢。這個算法可沒告訴你怎么處理的,你只能自己去想辦法。看到了,真正你做算法的過程中,不只是實現(xiàn),你需要面對的問題特別多,我是怎么做的呢?

  1. 將所有html標簽替換成空格,通過小空格切分后我們就能得到無數(shù)的小文本塊,然后我們就能做詞枚舉了
  2. 一個詞最長不能超過5個字
  3. 將中文,中英文,英文分開來做
  4. 將一些特殊字符 類似‘!¥……()+{}【】的呀啊阿哎吧和與兮呃唄咚咦喏啐喔唷嗬嗯噯你們我他她這是由于’ 這些不可能成詞的字符先去掉

這樣,詞集合就小多了。 接著就是按論文里的規(guī)則做計算了,比如算詞的凝固度,算重合子串。這里面還會遇到很多性能,或者內(nèi)存的坑,比如Spark里的groupByKey,reduceByKey。 我一開始省事,用了groupByKey,歇菜了,內(nèi)存直接爆了,為啥,你要去研究groupByKey到底是怎么實現(xiàn)的,一個詞出現(xiàn)幾十萬次,幾百萬次都很正常啊,groupByKey受不了這種情況。所以你得用reduceByKey。

很好,實現(xiàn)了算法后得到了結(jié)果,可人家沒告訴你,他貼出來的結(jié)果都是好看的,那是因為他是按頻次排的,但如果你拉到最后看,結(jié)果就不太好看了。這個時候你就需要觀察數(shù)據(jù)了,然后提出新的規(guī)則,比如最后得到的中文詞結(jié)果,我用了下面的規(guī)則過濾了下

 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"||

上面的規(guī)則是什么意思呢?凡是詞里面包含‘或’的,或者'就'的或者上面羅列的,我都認為這個詞是沒有意義的,經(jīng)過這個簡單規(guī)則一過濾,效果好非常多,很多沒什么意義的生活詞,或者不成詞的詞就被去掉了。中文,英文,中英文混合,我都加了很多這種規(guī)則,最終才過濾出了八萬計算機詞匯。

在多分類的算法中,貝葉斯和SVM的效果是相當不錯的,Spark中樸素貝葉斯的實現(xiàn)基于該論文: http://t.cn/RPkPkJq ,我看了一遍,在我的數(shù)據(jù)集上跑的效果并不好。我修改了論文中 p(t|c) 的公式 為 p(t|c) = 出現(xiàn)t的c分類下的文章數(shù)/c分類下得所有文章數(shù) 對于t|d=0的情況不參與計算。然后舍棄采用Log將乘除轉(zhuǎn)化為加減。分類效果得到明顯提高。

我把它應(yīng)用在了代碼篇的語言判斷上。給我一段代碼,我告訴你這是什么語言寫的。一開始識別率就達到70%左右,后面通過提高維度,將代碼片高維表示后(65萬),準確率提升到了85%??傮w而言,貝葉斯和SVM后面有人提出了各種改良,但是最后是改良了還是改差了,還得看具體數(shù)據(jù),你需要有調(diào)整他們的能力。

再說一個應(yīng)該說非常具有實際意義的一個算法:職位和簡歷匹配度算法。當然設(shè)計的是為了招聘研發(fā),所以基調(diào)就是以技能模型為主,提出一套完整匹配度算法。效果不錯。之后的研究人員基于我的算法,添加了職位方向等因子,使得效果更進一步。這套系統(tǒng)會成為后續(xù)招聘領(lǐng)域比較重要的基礎(chǔ)。

人生第一次跳槽

在上一家公司工作了五年之后(2015年8月),我終于跳槽了。當時老板(我們老板是一個非常優(yōu)秀的老板)請我吃飯的時候,問我為啥跳槽,我說我想開始做些事業(yè)。我能呆一家公司呆五年,說明老東家是真好。

我到了L公司之后,初期主要是實時計算這塊。實時計算能做的事情還是非常多的。這讓我后續(xù)以Spark Streaming 為起點,深入研究Spark 內(nèi)部源碼做好了鋪墊。

此時我除了負責一個應(yīng)用開發(fā)團隊,同時還負責內(nèi)部的機器學習團隊。然而我是一個很懶的人,不太適合帶團隊,我覺得我需要太多的時間投入到技術(shù)上去,去專研。所以團隊發(fā)展不足,這也讓自己很愧疚。然而只要和我工作過的人,我一定會讓他們有技術(shù)上的收獲。和我一起共事的同事有的去了百度,有的去了滴滴,大部分都還在互聯(lián)網(wǎng)公司。有一次吃飯的時候,他們有人說,雖然我很嚴苛,但是確實給他帶來了收獲。聽到這一點,我還是很開心的。技術(shù)人員應(yīng)該以技術(shù)為紐帶,互相幫助對方去提升。

這次跳槽唯一的遺憾之處在于,8月3號辦完離職,8月4號就開工上班,當天就加班了,ORZ。

Spark 的再相會

經(jīng)過八個月業(yè)余時間(周末加上工作日夜晚)的努力,我想要的產(chǎn)品原型終于做成了。然而終究是計劃有調(diào)整,在主動和一些CTO,資深技術(shù)人員,業(yè)已創(chuàng)業(yè)成功的人聊,加上碰了一些壁之后,我打算放慢些節(jié)奏。似乎光有個原型是不足以打動投資人的。

這個時候,Spark 對我的吸引力突然無限超越了事業(yè)對我的吸引力,所以三個月時間我寫了20幾篇Spark相關(guān)的文章,并且推動部門上了很多Spark Streaming相關(guān)的應(yīng)用。

在此期間,我大量閱讀源碼,并且修正了不少在特地情況下Spark會工作不正常的錯誤,同時做了一些增強。這些工作在Spark Streaming 的玫瑰與刺 有所提及。同時還提出了一個 流式計算動態(tài)資源調(diào)整算法

2016年3月份開始,我慢慢將工作重心放在多維查詢上,大體朝著SparkES 多維分析引擎設(shè)計 努力。5月份左右開源了StreamingPro項目,涵蓋了批處理,流式計算,交互式查詢等多項功能。其實原理也簡單,基于之前開源的ServiceframeworkDispatcher 實現(xiàn)配置化,使用以前開發(fā)的Serviceframework框架嵌入到Spark Driver 中,這樣就可以接管Spark UI的工作,提供新的交互接口。

技術(shù)的輪回

最近基于Spark Streaming + ElasticSearch 做數(shù)據(jù)的日志分析。還記得我12年(也可能是11年)引入ES做搜索,那個時候簡直被虐死,所以開發(fā)了一套自己的索引系統(tǒng)。沒想到四年后又遇到它了,而這個時候不在是在搜索領(lǐng)域,而是在大數(shù)據(jù)日志分析領(lǐng)域。人和技術(shù),都存在某種輪回。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容