團隊現場編程

組員職責分工

組員 職責
緒佩 組織分工、改進前端、後端、雲化
莊卉 改進前端、後端
家偉 算法關鍵詞識別、附加題實現
家燦 數據庫
一好 算法隨機數、算法審查
鴻傑 算法隨機數、算法審查
政演 提供算法思路、附加題idea思路、博客撰寫
凱琳 前端審查
丹丹 前端審查
青元 前端改進
宇恆 前端審查

github 的提交日誌截圖

github地址html

程序運行截圖

運行結果前端

抽獎結果名單java

程序運行環境

環境 名稱
操做系統 Windows10
編譯器 Eclipse javaee
本地服務器 Tomcat
數據庫 MySQL
可視化數據庫工具 Navicat

GUI界面

進入界面
c++

抽獎規則設定1
git

抽獎規則設定2
github

抽獎結果名單
web

錯誤提示
算法

發佈成功顯示
數據庫

基礎功能實現

本算法具備如下模式:

  • 不過濾模式:剔除機器,全部參與抽獎的人,都歸入開獎範圍。
  • 普通模式:篩除只參與抽獎而無發表任何原創言論的用戶(抽獎機器人),鼓勵你們積極參與有意義的發言。
  • 深度模式:爲了使發言更有意義,減小灌水,對如下用戶的中獎機率進行降權處理:
    • 只參與抽獎而無發表任何原創言論(抽獎機器人)
    • 只參與抽獎且只發送表情(水軍)

運行視頻

視頻連接:https://v.youku.com/v_show/id_XMzkyODA4NDY0OA==.html?spm=a2h0k.11417342.soresults.dtitle

隨機算法:

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的數據處理功能,在較小的空間開銷下,完成數據挖掘。

而且,該功能能夠鼓勵有意義的發言,減小惡意灌水等不良行爲。

實現

若是除去關鍵字後發送內容爲空斷定爲符合普經過濾規則,將除抽獎關鍵字外僅發送表情定義爲惡意灌水,標記爲num = 1,若是該id未出現過,存入map

private void handleMap(String talkContent) {
        boolean flag = true;
        int num = 0;
        if (filterType != 1) {
            talkContent = talkContent.replaceAll("#(.*)#", " ");
            //talkContent.replaceAll("、", " ");
            if (Pattern.matches("\\s*", talkContent)) { // 若是除去關鍵字後發送內容爲空-->符合普經過濾規則
                flag = false;
            /*將除抽獎關鍵字外僅發送表情定義爲惡意灌水,標記爲num = 1*/
            } else if (Pattern.matches("\\s*[\\[表情\\]]+\\s*", talkContent) && filterType == 3) {
                //System.out.println(talkContent);
                num = 1;
            }
        }
        if (!map.containsKey(userID) && flag) { // 若是該id未出現過
            map.put(userID, num); // 存入map
        } else if (num > 0) {
            num = (int) map.get(userID) + 1;
            map.put(userID, num);
        }
    }

發言爲空,剔出抽獎名單,惡意刷屏,下降權重,加入惡意灌水名單,由於文本中聊天樣本數據過少,一次灌水即踢出名單,如下是文本數據大時考慮修改,少許刷屏僅下降權重

if (en.getValue() < 0) {            //發言爲空,剔出抽獎名單
                i++;
                continue;
            } else if (en.getValue() > 0) {     //惡意刷屏,下降權重
                weight = en.getValue();
                if (weight > 0) {       
                    /*加入惡意灌水名單*/
                    //由於文本中聊天樣本數據過少,一次灌水即踢出名單
                    if (!uselessName.contains(en.getKey())) {   
                        uselessName.add(en.getKey());
                        x[i] = -1;
                        continue;
                    }
                    //如下是文本數據大時考慮修改,少許刷屏僅下降權重
                    if (weight > 30) {
                        weight = 30;
                    }
                }
                x[i] = (int) (x[i] * ((double)(30 - weight) / 30.0));
            }

實現效果

此處僅僅對該功能進行測試,因爲樣本數據不足,設定的閾值也較小,將黑名單的內容輸出到文件中能夠顯示以下內容:

附加功能二(迭代中)

咱們將該系統實如今雲端虛擬化設備上。用戶能夠在不一樣設備上調用該功能,便於產品的推廣使用和推廣。並且,人們經常忽略的是本地服務器的安全問題。本地服務器一般資源較少,安全機制不完善,一旦受到DDos攻擊,功能將癱瘓。而在雲端,有運營商提供良好的安全服務體系,大大提升安全性,保證系統可以正常運行。
咱們作了如下部署工做:

  1. 將雲端環境鏡像與本地環境匹配正確

  2. 雲端數據庫進行同步

  3. 將項目文件壓縮成wra形式傳至雲端

以上工做均正常操做完成

仍存在如下不足

瀏覽器沒法正常編譯jsp中嵌入的java代碼,致使和數據庫交互沒法實現,頁面之間跳轉出現bug。

雲端連接(仍在優化中):http://119.29.249.194/index.jsp

目前狀況:

附加功能三

本功能利用了Sketch對抽獎數據進行挖掘,能夠保持在高速條件下對海量數據的快速處理,節省空間資源。

背景

現抽獎的活動越多,參與抽獎的人數也愈來愈多。例如:王思聰抽獎微博的轉發量、評論數、點贊數均達到了兩千萬,總數達到了六千萬,對每一個抽獎帳號還須要維護巨大的數據量。當須要對該數據進行處理挖掘的時候,巨大的數據量將消耗巨大的空間和計算資源。然而,咱們有時候只須要部分的數據信息,例如:想了解每一個地區用戶的發言數,咱們並不須要記下每個用的發言數量,並將它們累加起來,在容許的偏差範圍內,只須要了解這個數量的近似值便可。對此,咱們的算法基於Sketch的算法,將巨大的數據散列到Skecth內,在有限的空間內完成巨大的數據計算,減小資源開銷。

引言

sketch 是一種基於散列的數據結構,能夠對海量數據,實時地存儲數據特徵信息,只佔用較小的空間資源,而且具有在理論上可證實的估計精度與內存的平衡特性。

Sketch的原理

sketch是基於散列的數據結構,經過設置散列函數,將具備相同散列值的鍵值數據存入相同的桶內,以減小空間開銷。桶內的數據值做爲測量結果,是真實值的近似。利用開闢二維地址空間,多重散列等技術減小散列衝突,提升測量結果的準確度。Count-Min 是一種典型的 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能夠實現呢

組員:翟丹丹

若是我能力強一些,那麼個人團隊就能夠更快更完美的完成這項項目。

組員:劉一好

若是給定時間長一點或者不在考試以前發佈這麼複雜的問題,那麼你們能更輕鬆愉快地完成這項任務。

組員:劉愷琳

若是能拿到相關教程,學習一段時間,那麼咱們就不會感受很慌張

組員:青元

若是能重來,那麼我必定要在課前學習,課上裝逼。

組員:莊卉

若是能重來一次,那麼我可能會選擇作自閉軟件或者直接自閉吧

組員:何宇恆

若是我再強一些,那麼個人團隊就能夠更開心的完成

組員:黃鴻傑

若是能重來一次,,那麼你們能更輕鬆愉快地完成這項任務。

組員:葛家燦

若是我再強一些,那麼咱們就不會感受很慌張

貢獻分評估

隊員名 貢獻度
胡緒佩 15%
周政演 11.5%
黃鴻傑 8%
葛家燦 9%
何宇恆 4%
胡青元 11.5%
劉一好 4%
劉愷琳 4%
翟丹丹 6%
何家偉 12%
莊卉 15%

PSP表格

PSP2.1 header 2 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 40 30
· Estimate ·估計這個任務須要多少時間 20 20
Development 開發 150 240
· Analysis 需求分析(包括學習新技術) 10 120
· 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
合計 680 1410

我的學習進度條

第N周 新增代碼(行) 累計代碼(行) 本週學習耗時(小時) 累計學習耗時(小時) 重要成長
1 391 391 25 25 複習c++,學習單元測試和代碼覆蓋率,更熟悉Visual Studio的使用
2 100 491 5 30 在優化代碼和改bug
3 0 0 15 45 閱讀《構建之法》第三章和第八章,學習使用Axure RP8,對UI設計有進一步瞭解和認識,對項目開發架構進一步的理解
4 441 932 25 70 對爬蟲初步認識,還有待學習(隊友負責模塊),Debug能力++;
5 0 932 15 85 詳細瞭解需求規格說明書以及接口文檔書寫
6 232 1164 20 105 學習基礎前端界面佈局及學習思惟導圖製做
7 597 1761 20 125 學習前端交互,查資料能力++,對前端認識愈來愈深,恐懼愈來愈大,懂得作一個項目的艱難!
相關文章
相關標籤/搜索