這些年,我工作上走過的路
常常的,我會感恩于我所在的公司,讓自己經歷了種種。很多情況下,公司的成長帶動了自己的成長。完整的跟著公司經歷大數據業務從無到有,從有到精,這種歷程就像美味的食物,吃過了才能真正感覺,而文字是不足以表達的。
我走過了畢業季,創業征途,踏進開源之路,轉型進入大數據,到最后有緣接觸機器學習。每個章節,我都會提及對應那個階段對技術的感悟,自己做的一些具體事情。
到寫這篇文章為止,我發現經過這八年,我依然沒有懈怠下來,我依然在狂奔。
畢業季
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做搜索,那個時候簡直被虐死,所以開發了一套自己的索引系統。沒想到四年后又遇到它了,而這個時候不在是在搜索領域,而是在大數據日志分析領域。人和技術,都存在某種輪回。
來自: http://www.jianshu.com/p/9e0aba6eaaa1