因為最近在練Rails3 + MongoDB,於是選了這個當作自己練習的題目,專案名稱暫定為"AlgoCat",也就是「演算貓」(Algorithm Cat)。這個名字是想告訴自己「在演算法的世界中,一隻大貓努力向上爬」。AlgoCat的目標為「追踨算法競賽的活動及競賽成績,並標記算法競賽及題庫中,解過及待學習的題目」。
AlgoCat還相當的不完整,可以說還在Pre-Alpha的階段吧。目前AlgoCat提供的功能僅有:查詢TopCoder Algorithm Rating的排行、觀看TopCoder使用者的成績記錄、追踨某些特定的TopCoder使用者並進行比較(以折線圖方式呈現)。
這篇文章其實不是打算announce這個網站,而是將自己的開發筆記整理一下。目前的成果可以在algocat.heroku.com看到。
Environment & Framework
- Rails 3
- MongoDB
- Mongoid
- Devise
Fetching Data from TopCoder
TopCoder本身提供了XML Feed的介面,用Ruby抓取資料只要簡單地用Net::HTTP和和REXML即可。
由於AlgoCat並不是一開始就抓好TopCoder的所有資料。有些資料是等使用者查詢才向TopCoder抓,並存放在資料庫。這方面的行為應該用Delayed Job之類的方法放在背景處理。AlgoCat在開發初期就有想到這點,但因為早期開發實作方便,還是暫時在前景處理。之後會移到background task去。BTW, Heroku第一隻worker就要收錢....之後可能會想些替代方案。
Mongoid
基本上照著官網的教學,應該可以做到大部份的功能。但要用NoSQL的資料庫,只學Object Mapper而不了解資料庫本身,應該會造成最佳化的困難。討論一些我踩到的問題好了:
@users = User.asc(:rating).limit(10)
現在,呼叫多次@users.each,其實會造成多次的query。解決方法官網有寫,只要呼叫cache,或是直接@user=@user.to_a亦可
上面這個算是小問題,只是要熟析Mongoid的細節。但另一個問題是Mongoid缺乏了對MongoDB的一些簡單低階操作。舉例來說,如果db中有一個articles的collection,而每篇文章中有一個以tags為key的array,array中存放了tag的字串。依MongoDB的官方教學,要增加一個tag的query可以這樣下:
db.articles.update( { title: "Rails3" }, { $addToSet : { tags: "Web" } } );
或者這樣亦可
db.articles.update( {title: "Rails3", tags: {"$ne": "Web"}}, {"$push": { tags : "Web" } } );
這兩者者可以確保「在文章原本沒有該tag的情況下,將tag插入」
但Mongoid的封裝似乎只支援這樣的動作:
article = Article.where( :title=>"Rails3" ).first
unless article.tags.elem? then
article.tags << Devise
article.save
end
原本是DB上的一個query,變成一定要將資料拉回app server判斷,再將「所有tags」寫回去,效能應有不小的差距。
Rails jquery-ujs
Rails內建了一些與JavaScript&AJAX相關的helpers,並以rails.js與prototyle javascript library橋接。如果想用jQuery,又想保留rails的helpers功能的話,可以用jquery-ujs中的rails.js將原本的蓋掉,就可以將原本prototype相關的javascript刪掉,換上jquery。
AlgoCat目前的「追踨使用者」(Watch)功能是用AJAX + jQuery做的。
Chart Library
要在網頁中繪製圖表,目前應該有三大主流:
1.在Server端繪製圖表,再傳送圖片到Client端
2.萬惡Flash (?)
3.以JavaScript為基礎,操作HTML Canvas之類的方式繪作圖表
其中第一點是傳統的方法,從以前的GnuPlot,到現在可以把資料丟到雲裡給Google畫圖(Google Chart API),但其缺點是比較不容易做圖表的互動操作。我個人不喜歡使用Flash作圖表,覺得多了一層整合上的麻煩,而且有點拖慢網頁的速度,但Flash應是最容易實作圖表互動操作的方式。而隨著瀏覽器對Canvas的支援趨近完整,JavaScript Engine運行的速度越來越快,用JavaScript在Client繪製圖表也成了選擇之一。而且靠JavaScript及DOM,同樣也可以進行與圖表的互動操作。
在開發AlgoCat時,一開始我選擇嘗試googlecharts gem,結果發現目前的版本還滿雷的。首先,我遇到了Linc Chart中,y軸座標值完全不對的問題。後來我發現其實這個Issue是同一個問題。試了一下後,決定git clone一份googlecharts下來,git bisect找bug。後來是把這個問題修掉了,但似乎還有其他小問題存在。之後有空應該會整理一下,發patch或pull request吧…
後來考慮到可能要在圖表上做互動,所以還是換回JavaScript-based的flot。Flot是一套以jQuery為基礎的JavaScript Plotting Library。
BTW,因為flot相依於jQuery,所以rails內建的Prototype一定要移掉,不然會相衝。我使用了前段提到的jquery-ujs。
Ongoing work
目前最大的問題,應該就是Fetch XML DATA應該要放在背景做吧。然後會補強自動更新的機制、加上Codeforces或Uva題庫功能等…
Source Code?
目前還沒有打算open source,而且可能還會大規模的重構,等我整理好code後有可能會open。
沒有留言:
張貼留言