团队现场编程

组员职责分工

组员 职责
绪佩 组织分工、改进前端、后端、云化
庄卉 改进前端、后端
家伟 算法关键词识别、附加题实现
家灿 数据库
一好 算法随机数、算法审查
鸿杰 算法随机数、算法审查
政演 提供算法思路、附加题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 学习前端交互,查资料能力++,对前端认识愈来愈深,恐惧愈来愈大,懂得作一个项目的艰难!
相关文章
相关标签/搜索