1. 程式人生 > >現場編程

現場編程

() 其他 form 成長 審查 proc rim 為我 行數

目錄

  • 組員職責分工
  • 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個計數器中的最小值,作為計算的最終值。
技術分享圖片

設計考量

測量值偏大:使用哈希的方法會產生沖突,多個數據哈希到同一個桶內,那麽這個桶的計數值就會偏大。

  1. 為什麽允許有誤差:在大量數據條件下,若把所有信息都準確地記錄下來,要消耗大量計算和空間開銷,無法滿足實時性;而且在很多情況下,並不需要非常精確的數據,在一定程度上可靠的估計值,便足以滿足需求。

  2. 為什麽要設置多個哈希函數:如果只設置一個哈希函數,多個流數據存入同一個桶,誤差就會很大。通過設計多個哈希函數,減少哈希值的沖突,以減少誤差。每個流都要經過所有哈希函數的處理,存入不同的計數器中。計數器的最小值雖然還是大於等於真實值,但最接近真實值。這也是 “ Count-Min ”的由來。

  3. 哈希函數個數:哈希函數越多,沖突越少,測量值越精確,但計算開銷大。需要權衡測量精度和準確度,來設置合適的哈希函數個數。

解決方法

  1. 使用Sketch的方法,對數據進行處理,對文本數據進行處理後,設置好參數,使用多個散列函數對數據進行處理,將數據的出現次數存入桶內。以此我們的算法基於Sketch的算法,將巨大的數據散列到Skecth內,在有限的空間內完成巨大的數據計算,減少資源開銷。

  2. 將CM-Sketch實現在抽獎系統當中,可以通過調整輸入的兩個參數值對空間資源和計算準確度進行近似:
  • eps (for error), 0.01 < eps < 1
  • gamma (probability for accuracy), 0 < gamma < 1

通過輸入eps和gamma值,可以根據自己的系統環境調整資源開銷。由於估計該測試環境的資源開銷大小,需要具備良好的數學知識,並且對個方面數據進行評估計算。我們將空間開銷抽象封裝成錯誤估計值和精確度。只需要對自己的需求估計,確定該參數值,就可以滿足對空間開銷的確定。

  1. 完成了某個處理場景,對抽獎文本進行處理,得出每個用戶的發言次數。

實現效果

以下是處理抽獎數據的類的定義:

 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));

效果截圖

技術分享圖片

技術分享圖片

以上是算法得出的效果截圖,兩張圖的結果幾乎相同,少數數據略有不同,驗證了該算法的近似性

鼓勵有想法且有用的功能

為鼓勵有意義的發言,我們
技術分享圖片

遇到的困難及解決方法

組員:胡緒佩

困難

  1. 分工沒有分很合理;
  2. 分好工的準備的不夠充分;
  3. 和隊友交流不夠密切及時,導致他們誤入歧途寫了很久效率卻還很低;
  4. JavaWeb不熟悉,差不多全忘了...重頭再寫很艱難;
  5. web界面細節布局還是處理的不夠好,所以界面還挺醜;
  6. 其他作業、考試實在太多,忙不過來;
  7. 軟工這麽多項目,已經占用了太多太多其他學科的時間了;

解決辦法

  1. 下次盡力在開始的時候明確合理分工;
  2. 爭取高效率、及時的和隊友交流(這次是因為下午有實驗,隊友直接就默默地開始打);
  3. 重頭寫也不難,不就是通個宵嗎?
  4. 盡量把軟工規定在每天什麽時間做吧,不能再占用過多其他的時間了。大學不僅僅只有軟工實踐;
  5. 考試優先,考後熬夜;

組員:莊卉

困難:alpha還在單機階段課堂實戰已經進入web,時間分配不均,分工出現混亂,作為後端負責人沒有檢查環境軟件版本甚至不少人沒有某某軟件,導致不熟悉。

解決辦法:冷靜冷靜冷靜,盡量不焦慮,事情一件一件來(嗯,體會到了瀕臨死亡的感覺)

組員:周政演

困難:時間太短,對代碼要求很高,不允許叠代修改bug。算法全新,需要構思。附加題構思。

解決辦法:考慮到前一段學習的djb2散列函數,修改使用LCG線性同余法,解決隨機數的問題。考慮在實際場景下,微博轉發數量太大,要進行數據挖掘等工作,需要耗費很大計算和空間資源,故使用LCG和Sketch解決。

組員:劉一好

困難:隨機數生成算法需要從網上查閱很多相關資料,需要同後端使用相同的類和傳參方式

組員:翟丹丹

困難
1.編碼方面,在其他人面前,真的是有點過於弱。
2.前端方面,淺顯的還能寫出來,深度一點的就會一直出bug。
3.擅長的東西過於單一,理解的知識也是過於膚淺,個人能力有待提升。

解決辦法
1.看教程,一步步來。
2.看隊友操作,積累經驗。

解決辦法:在網上查找代碼,並同其他同學交流,制定相同的傳參規則

組員:劉愷琳

困難:前端界面太不友好,不了解代碼,修改起來有難度。與後端交接時,返回值有待商榷。

解決辦法:查看網上代碼,下載模板進行修改。

組員:青元

困難

  1. 不會寫java,要現學
  2. 不會寫html和css,要現學

解決辦法

  1. 只能盡量學。

組員:葛家燦

困難

  1. 對於javaweb的0知識量,導致的無從下手
  2. 動態html頁面的實現
  3. 頁面之間跳轉之後,怎麽做到向新頁面傳遞信息

解決辦法

  1. 用servlrt實現一個動態頁面的out,頁面的數據數據從服務器的數據庫中導出
  2. 用到
    中的action觸發servlet,在form中使用type=hidden,作為一個隱藏域,傳遞它的value給servlet
  3. 有函數可以直接實現,服務器內部的頁面跳轉

組員:何家偉

困難:對於抽獎應該如何實現沒有頭緒

解決辦法:求助了組內的周政演和黃鴻傑同學

組員:黃鴻傑

困難

  1. 關於線性同余法的了解很粗淺
  2. 關於JAVA的String和DATE之間的轉換
  3. 網絡上基本上都是偽代碼,在轉化成JAVA代碼過程中各種參數不知道怎麽設置

解決辦法

  1. 稍微熟悉了JAVA代碼的書寫
  2. 修改網絡博客上的轉換實例符合項目的需求
  3. 找博客看原理,茫茫大海裏面找到了有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 構思了隨機算法、附加功能算法和具體思路,完成撰寫敘述

現場編程