現場編程
目錄
- 組員職責分工
- github 的提交日誌截圖
- 程序運行截圖
- 程序運行環境
- GUI界面
- 基礎功能實現
- LCG算法
- 過濾(降權)算法
- 算法思路
- 紅黑樹
- 附加功能實現
- 背景
- 引言
- 解決方法
- 實現效果
- 效果截圖
- 鼓勵有想法且有用的功能
- 遇到的困難及解決方法
- 組員:胡緒佩
- 組員:莊卉
- 組員:周政演
- 組員:劉一好
- 組員:翟丹丹
- 組員:劉愷琳
- 組員:青元
- 組員:葛家燦
- 組員:何家偉
- 組員:黃鴻傑
- 組員:何宇恒
- 馬後炮
- 組員:胡緒佩
- 組員:何家偉
- 組員:周政演
- 組員:翟丹丹
- 組員:劉一好
- 組員:劉愷琳
- 組員:青元
- 組員:莊卉
- 組員:何宇恒
- 組員:黃鴻傑
- 組員:葛家燦
- 貢獻分評估
- PSP表格
- 學習進度表
組員職責分工
組員 | 職責 |
---|---|
緒佩 | 組織分工、改進前端、後端、雲化 |
莊卉 | 改進前端、後端 |
家偉 | 算法關鍵詞識別、附加題實現 |
家燦 | 數據庫 |
一好 | 算法隨機數、算法審查 |
鴻傑 | 算法隨機數、算法審查 |
政演 | 提供算法思路、附加題idea思路、博客撰寫 |
凱琳 | 前端審查 |
丹丹 | 前端審查 |
青元 | 前端改進 |
宇恒 | 前端審查 |
github 的提交日誌截圖
github地址
程序運行截圖
運行結果
抽獎結果名單
程序運行環境
環境 | 名稱 |
---|---|
操作系統 | Windows10 |
編譯器 | Eclipse javaee |
本地服務器 | Tomcat |
數據庫 | MySQL |
可視化數據庫工具 | Navicat |
GUI界面
進入界面
抽獎規則設定1
抽獎規則設定2
抽獎結果名單
錯誤提示
發布成功顯示
基礎功能實現
本算法具有以下模式:
- 不過濾模式:剔除機器,所有參與抽獎的人,都納入開獎範圍。
- 普通模式:篩除只參與抽獎而無發表任何原創言論的用戶(抽獎機器人),鼓勵大家積極參與有意義的發言。
- 深度模式:為了使發言更有意義,減少灌水,對以下用戶的中獎概率進行降權處理:
- 只參與抽獎而無發表任何原創言論(抽獎機器人)
- 只參與抽獎且只發送表情(水軍)
隨機算法:
LCG算法
我們的抽獎算法基於LCG算法,LCG(linear congruential generator)線性同余算法,是一個古老的產生隨機數的算法。
本算法有以下優點:
- 計算速度快:抽獎時的算法時間復雜度是一個較大的問題,在微博開獎的時候,由於抽獎人數眾多,(例如王思聰的抽獎微博,轉發量、評論數、點贊數均達到了兩千萬,總數達到了六千萬,輸入量十分巨大)所以常常需要花費幾十分鐘的時間開獎,如此的算法性能是難以忍受的。對此,我們的算法基於LCG算法,利用其速度優勢,減少開獎時間。
- 易於實現:算法易於理解,可以通過改變取余數來控制算法的空間復雜度與隨機分布效果。且算法是線性的算法,和非線性的模型相比,具有較低的復雜度。
- 易於推廣:本算法改變取余參數,對空間資源和隨機準確率權衡,根據不同的設備資源和計算能力調優,具有很強的靈活性,易於使用推廣。
本算法基於的LCG算法由以下參數組成:
參數 | m | a | c | X |
---|---|---|---|---|
性質 | 模數 | 乘數 | 加數 | 隨機數 |
作用 | 取模 | 移位 | 偏移 | 作為結果 |
LCG算法是如下的一個遞推公式,每下一個隨機數是當前隨機數向左移動 log2 a 位,加上一個 c,最後對 m 取余,使隨機數限制在 0 ~ m-1 內
從該式可以看出,該算法由於構成簡單,具有以下優點:
- 計算速度快
- 易於實現
- 易於寫入硬件
以下是針對不同參數 lcg 產生隨機數的效果圖
可以看出,針對不同的參數,lcg產生的效果差別很大
以下是針對不同環境下的參數選擇
根據我們機器的情況,我們選擇使用參數:
過濾(降權)算法
算法思路
抽獎算法對兩種情況進行了處理:
無發言剔除:當用戶只轉發抽獎關鍵字,而沒有相關發言時,直接剔出抽獎名單。
惡意刷屏:抽獎者可以自行定義一個抽獎閾值φ1,當發言數超過φ1時,對該用戶進行中獎概率降權處理。
灌水剔除:抽獎者可以自行定義一個抽獎閾值φ2,發送的表情數超過閾值的時候,判定為灌水,剔出抽獎名單
for (Map.Entry<String, Integer> en : map.entrySet()) {
//System.out.println(en.getKey() + "=" + en.getValue());
x[i] = ( a * x[i-1] + b ) % m;
if (en.getValue() < 0) { //發言為空,剔出抽獎名單
i++;
continue;
} else if (en.getValue() > 0) { //惡意刷屏,降低權重
weight = en.getValue();
if (weight > 30) {
weight = 30;
}
x[i] = (int) (x[i] * ((double)(30 - weight) / 30.0));
}
map.put(en.getKey(), x[i]);
//System.out.println(en.getKey() + "=" + en.getValue());
i++;
}
紅黑樹
紅黑樹是一種自平衡的二叉查找樹,是一種高效的查找樹。
提供良好的效率:可在O(logN)時間內完成查找、增加、刪除等操作,能保證在最壞情況下,基本的動態幾何操作的時間均為O(lgn)。只要求部分地達到平衡要求,降低了對旋轉的要求,任何不平衡都會在三次旋轉之內解決,從而提高了效率。抽獎伏安法涉及大量增刪改查操作,紅黑樹算法提供了良好的效率支撐。
提供性能下限保證:相比於BST,紅黑樹可以能確保樹的最長路徑不大於兩倍的最短路徑的長度,可見其查找效果的最低保證。最壞的情況下也可以保證O(logN)的復雜度,好於二叉查找樹O(N)復雜度。在大數據量情況下,紅黑樹算法為抽獎算法提供良好的性能保證。
提供詞頻統計的高性能:紅黑樹的算法時間復雜度和AVL樹相同,但統計性能更高。插入 AVL樹和紅黑樹的速度取決於所插入的數據。在數據比較雜亂的情況,則紅黑樹的統計性能優於AVL樹。在抽獎時時,數據分布較為雜亂,在此應用場景下,紅黑樹算法與抽獎器契合。
提供較小的資源開銷:與基於哈希的算法相比,基於紅黑樹方法帶來更小的資源開銷,程序消耗內存較少。哈希的算法占用大量資源,需要維護大量的計數器,並且在哈希過程中消耗了大量的計算資源。抽獎系統器消耗的資源較少。
附加功能實現
本功能利用了Sketch對抽獎數據進行挖掘,可以保持在高速條件下對海量數據的快速處理,節省空間資源。
背景
現抽獎的活動越多,參與抽獎的人數也越來越多。例如:王思聰抽獎微博的轉發量、評論數、點贊數均達到了兩千萬,總數達到了六千萬,對每個抽獎賬號還需要維護巨大的數據量。當需要對該數據進行處理挖掘的時候,巨大的數據量將消耗巨大的空間和計算資源。然而,我們有時候只需要部分的數據信息,例如:想了解每個地區用戶的發言數,我們並不需要記下每一個用的發言數量,並將它們累加起來,在允許的誤差範圍內,只需要了解這個數量的近似值即可。對此,我們的算法基於Sketch的算法,將巨大的數據散列到Skecth內,在有限的空間內完成巨大的數據計算,減少資源開銷。
引言
sketch 是一種基於散列的數據結構,可以對海量數據,實時地存儲數據特征信息,只占用較小的空間資源,並且具備在理論上可證明的估計精度與內存的平衡特性。
Sketch的原理
sketch是基於散列的數據結構,通過設置散列函數,將具有相同散列值的鍵值數據存入相同的桶內,以減少空間開銷。桶內的數據值作為測量結果,是真實值的近似。利用開辟二維地址空間,多重散列等技術減少散列沖突,提高測量結果的準確度。Count-Min[7] 是一種典型的 sketch ,在 2004 年被提出。
實際上 Count-Min sketch 用到的是分類的思想:將具有相同哈希值的key歸為一類,並使用同一個計數器計數。
當數據到來時,逐個記錄所有數據的信息,會帶來巨大的計算和空間資源開銷。而我們的功能往往也無需記錄所有的信息。
基於CM-Sketch實現
Count-Min sketch由多個哈希函數(f1……fn)和一張二維表組成。二維表的每個存儲空間維護了一個計數器,其中每個哈希函數分別對應表中的每一行。當數據到來時,需要經過每個哈希函數 f1……fn 的處理,根據處理得到的哈希值分別存入每一行對應哈希值的計數器。有幾個哈希函數,就要計算幾次。算完後,取這m個計數器中的最小值,作為計算的最終值。
設計考量
測量值偏大:使用哈希的方法會產生沖突,多個數據哈希到同一個桶內,那麽這個桶的計數值就會偏大。
為什麽允許有誤差:在大量數據條件下,若把所有信息都準確地記錄下來,要消耗大量計算和空間開銷,無法滿足實時性;而且在很多情況下,並不需要非常精確的數據,在一定程度上可靠的估計值,便足以滿足需求。
為什麽要設置多個哈希函數:如果只設置一個哈希函數,多個流數據存入同一個桶,誤差就會很大。通過設計多個哈希函數,減少哈希值的沖突,以減少誤差。每個流都要經過所有哈希函數的處理,存入不同的計數器中。計數器的最小值雖然還是大於等於真實值,但最接近真實值。這也是 “ Count-Min ”的由來。
哈希函數個數:哈希函數越多,沖突越少,測量值越精確,但計算開銷大。需要權衡測量精度和準確度,來設置合適的哈希函數個數。
解決方法
使用Sketch的方法,對數據進行處理,對文本數據進行處理後,設置好參數,使用多個散列函數對數據進行處理,將數據的出現次數存入桶內。以此我們的算法基於Sketch的算法,將巨大的數據散列到Skecth內,在有限的空間內完成巨大的數據計算,減少資源開銷。
- 將CM-Sketch實現在抽獎系統當中,可以通過調整輸入的兩個參數值對空間資源和計算準確度進行近似:
- eps (for error), 0.01 < eps < 1
- gamma (probability for accuracy), 0 < gamma < 1
通過輸入eps和gamma值,可以根據自己的系統環境調整資源開銷。由於估計該測試環境的資源開銷大小,需要具備良好的數學知識,並且對個方面數據進行評估計算。我們將空間開銷抽象封裝成錯誤估計值和精確度。只需要對自己的需求估計,確定該參數值,就可以滿足對空間開銷的確定。
- 完成了某個處理場景,對抽獎文本進行處理,得出每個用戶的發言次數。
實現效果
以下是處理抽獎數據的類的定義:
public class CountMinSketch {
private static final long LONG_PRIME = 4294967311l;
private int width;
private int depth;
/**
* eps(for error), 0.01 < eps < 1 the smaller the berrer
*/
private double eps;
/**
* gammga(probability for accuracy), 0 < gamma < 1 the bigger the better
*/
private double gamma;
/**
* used in generation of hash funtion
*/
private int aj;
private int bj;
private int total;
/**
* array of arrays of counters
*/
//private HashMap<String, Integer> C = new HashMap<>();
private int[][] C;
private int[][] C2;
/**
* array of hash values for particular item contians two element arrays {aj,
* bj}
*/
private int[][] hashes;
public CountMinSketch(double eps, double gamma) {
this.eps = eps;
this.gamma = gamma;
width = (int) Math.ceil(Math.exp(1.00) / eps);
depth = (int) Math.ceil(Math.log(1.00 / gamma));
total = 0;
C = new int[depth][width];
C2 = new int[depth][width];
initHashes();
}
其中,以下部分完成了調整兩個參數值對空間資源和計算準確度的權衡:
/**
* eps(for error), 0.01 < eps < 1 the smaller the berrer
*/
private double eps;
/**
* gammga(probability for accuracy), 0 < gamma < 1 the bigger the better
*/
private double gamma;
width = (int) Math.ceil(Math.exp(1.00) / eps);
depth = (int) Math.ceil(Math.log(1.00 / gamma));
效果截圖
以上是算法得出的效果截圖,兩張圖的結果幾乎相同,少數數據略有不同,驗證了該算法的近似性
鼓勵有想法且有用的功能
為鼓勵有意義的發言,我們
遇到的困難及解決方法
組員:胡緒佩
困難:
- 分工沒有分很合理;
- 分好工的準備的不夠充分;
- 和隊友交流不夠密切及時,導致他們誤入歧途寫了很久效率卻還很低;
- JavaWeb不熟悉,差不多全忘了...重頭再寫很艱難;
- web界面細節布局還是處理的不夠好,所以界面還挺醜;
- 其他作業、考試實在太多,忙不過來;
- 軟工這麽多項目,已經占用了太多太多其他學科的時間了;
解決辦法
- 下次盡力在開始的時候明確合理分工;
- 爭取高效率、及時的和隊友交流(這次是因為下午有實驗,隊友直接就默默地開始打);
- 重頭寫也不難,不就是通個宵嗎?
- 盡量把軟工規定在每天什麽時間做吧,不能再占用過多其他的時間了。大學不僅僅只有軟工實踐;
- 考試優先,考後熬夜;
組員:莊卉
困難:alpha還在單機階段課堂實戰已經進入web,時間分配不均,分工出現混亂,作為後端負責人沒有檢查環境軟件版本甚至不少人沒有某某軟件,導致不熟悉。
解決辦法:冷靜冷靜冷靜,盡量不焦慮,事情一件一件來(嗯,體會到了瀕臨死亡的感覺)
組員:周政演
困難:時間太短,對代碼要求很高,不允許叠代修改bug。算法全新,需要構思。附加題構思。
解決辦法:考慮到前一段學習的djb2散列函數,修改使用LCG線性同余法,解決隨機數的問題。考慮在實際場景下,微博轉發數量太大,要進行數據挖掘等工作,需要耗費很大計算和空間資源,故使用LCG和Sketch解決。
組員:劉一好
困難:隨機數生成算法需要從網上查閱很多相關資料,需要同後端使用相同的類和傳參方式
組員:翟丹丹
困難:
1.編碼方面,在其他人面前,真的是有點過於弱。
2.前端方面,淺顯的還能寫出來,深度一點的就會一直出bug。
3.擅長的東西過於單一,理解的知識也是過於膚淺,個人能力有待提升。
解決辦法:
1.看教程,一步步來。
2.看隊友操作,積累經驗。
解決辦法:在網上查找代碼,並同其他同學交流,制定相同的傳參規則
組員:劉愷琳
困難:前端界面太不友好,不了解代碼,修改起來有難度。與後端交接時,返回值有待商榷。
解決辦法:查看網上代碼,下載模板進行修改。
組員:青元
困難:
- 不會寫java,要現學
- 不會寫html和css,要現學
解決辦法:
- 只能盡量學。
組員:葛家燦
困難:
- 對於javaweb的0知識量,導致的無從下手
- 動態html頁面的實現
- 頁面之間跳轉之後,怎麽做到向新頁面傳遞信息
解決辦法
- 用servlrt實現一個動態頁面的out,頁面的數據數據從服務器的數據庫中導出
- 用到中的action觸發servlet,在form中使用type=hidden,作為一個隱藏域,傳遞它的value給servlet
- 有函數可以直接實現,服務器內部的頁面跳轉
組員:何家偉
困難:對於抽獎應該如何實現沒有頭緒
解決辦法:求助了組內的周政演和黃鴻傑同學
組員:黃鴻傑
困難:
- 關於線性同余法的了解很粗淺
- 關於JAVA的String和DATE之間的轉換
- 網絡上基本上都是偽代碼,在轉化成JAVA代碼過程中各種參數不知道怎麽設置
解決辦法:
- 稍微熟悉了JAVA代碼的書寫
- 修改網絡博客上的轉換實例符合項目的需求
- 找博客看原理,茫茫大海裏面找到了有JAVA示例的代碼修改
組員:何宇恒
困難:對於web很麽有經驗,對於排版,真的難為我這個男生
解決辦法:找了一個婚慶的模板套了一下,改了些字和圖
馬後炮
由於本次現場編程開發進度低於預期,給每位同學一個一句話吐槽機會,格式為:如果……,那麽……
組員:胡緒佩
如果能睡一個好覺,那麽我會補一個月的覺
組員:何家偉
如果我有好好學搜索引擎或者好好看前端,那麽這次作業大家做起來都會快很多
組員:周政演
如果時間長一點,那麽我還有很多idea可以實現呢
組員:翟丹丹
如果我能力強一些,那麽我的團隊就可以更快更完美的完成這項項目。
組員:劉一好
如果給定時間長一點或者不在考試之前發布這麽復雜的問題,那麽大家能更輕松愉快地完成這項任務。
組員:劉愷琳
如果能拿到相關教程,學習一段時間,那麽我們就不會感覺很慌張
組員:青元
如果能重來,那麽我一定要在課前學習,課上裝逼。
組員:莊卉
如果能重來一次,那麽我可能會選擇做自閉軟件或者直接自閉吧
組員:何宇恒
如果我再強一些,那麽我的團隊就可以更開心的完成
組員:黃鴻傑
如果能重來一次,,那麽大家能更輕松愉快地完成這項任務。
組員:葛家燦
如果我再強一些,那麽我們就不會感覺很慌張
貢獻分評估
以下部分計入個人得分:
PSP表格
PSP2.1 | header 2 | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 40 | 30 |
? Estimate | ?估計這個任務需要多少時間 | 20 | 20 |
Development | 開發 | 150 | 240 |
? Analysis | 需求分析(包括學習新技術) | 60 | 60 |
? Design Spec | ? 生成設計文檔 | 0 | 0 |
? Design Review | ? 設計復審 | 0 | 0 |
? Coding Standard | ? 代碼規範 (為目前的開發制定合適的規範) | 0 | 0 |
? Design | ? 具體設計 | 180 | 150 |
? Coding | ? 具體編碼 | 120 | 600 |
? Code Review | ? 代碼復審 | 30 | 120 |
? Test | ?測試(自我測試,修改代碼,提交修改) | 100 | 100 |
Reporting | 報告 | 10 | 10 |
? Test Repor | ? 測試報告 | 0 | 0 |
? Size Measurement | ? 計算工作量 | 0 | 0 |
? Postmortem & Process Improvement Plan | ? 事後總結, 並提出過程改進計劃 | 20 | 20 |
合計 | 730 | 1350 |
學習進度表
第N周 | 新增代碼(行) | 累計代碼(行) | 本周學習耗時(小時) | 累計學習耗時(小時) | 重要成長 |
---|---|---|---|---|---|
1 | 0 | 0 | 5 | 5 | 閱讀《構建之法》,重點了解了 NABCD 模型 |
2 | 0 | 0 | 10 | 15 | 找到了適合團隊的原型工具,以及如何並行操作 |
3 | 68 | 68 | 6 | 6 | python字符處理復習、爬蟲學習 |
4 | 78 | 146 | 7 | 13 | java爬蟲學習 |
5 | 194 | 340 | 6 | 19 | 單元測試設計 |
6 | 0 | 340 | 10 | 29 | 需求報告撰寫 |
7 | 0 | 340 | 5 | 34 | Alpha博客撰寫 |
7 | 0 | 340 | 3 | 37 | Alpha2博客審查 |
7 | 0 | 340 | 3 | 40 | Alpha3博客審查 |
7 | 50 | 390 | 10 | 50 | 構思了隨機算法、附加功能算法和具體思路,完成撰寫敘述 |
現場編程