在營銷活動中的抽獎算法放送

做秒殺的深有體會

做抽獎的深有體會

體會什麼?

獎品不一會兒就被抽光了??納尼(一臉懵逼)

說好的這些獎品要維持一天呢!!

去數據庫查查去~

這貨怎麼能有兩個訂單??不是說好的一個用戶只能抽獎一次麼!!(沮喪臉)

這貨又是誰?他們的名字怎麼那麼相似??(挖日)

 

感覺要被老闆艹翻了!我出1毛錢誰能幫我砍X老闆,在線等,急~(滑稽臉)

下面言歸正傳

在做營銷活動時候會經常遇到上面這些情況,咋辦。

一、對於同一個用戶能違規提交多個訂單的情況

    在用戶抽獎時候都要檢測一下用戶上次抽獎產生的標識符,比如在緩存中存儲的一個值。比如這個樣子

  Util.CacheManager.InsertCache(KeyName + UserModel.ID,"1", DateTime.Now.AddSeconds(10));  

  如果下次抽獎的時候這個值還在,說明兩次抽獎間隔小於10s,那麼給與相關提示,比如:抽獎關於頻繁拉

  驗證通過後進入下一步。

  爲用戶生成一個標誌,在緩存中,對緩存的插入操作一定要是線程安全的,(線程安全圈起來這是重點,要考)。比如這樣:

 

 object timeobje =  Util.CacheManager.GetCache(KeyName + UserModel.ID); 

  當然你也可以使用redis,memcached 等緩存服務來實現這種方式。

  引申一下你可以使用樂觀鎖來實現:用戶請求進入時候爲用戶創建一個標識值,插入訂單前判斷這個值是否變化,變化了,放棄本次操作,未變化,繼續本次操作。

  redis,memcached 都提供有相關功能。

 

  使用了上述手段就能完全避免惡意的提交麼? 否  ,但是能解決絕大部分惡意的提交

  有沒有完全的解決方案? 我這裏暫時沒有

 

  你也可以參考他們的文章:

  http://blog.csdn.net/zlhzhj/article/details/51245807

  http://blog.csdn.net/lvqingyao520/article/details/52974217

 

二、多個相類似的用戶,通過正常的流程進行活動

  通過實名認證來解決?   優點:可以98%的規避機器人註冊賬號和提高用戶的真實性 。 缺點:認證成本高,流程麻煩,用戶粘性小,不適合營銷活動

  封IP?有點:能屏蔽部分非法註冊和非法參與活動的人。  缺點:使用代理的用戶可以輕鬆繞過,會誤傷同一個局域網的用戶,比如同一個辦公室的

  通過算法分析用戶行爲?優點:可靠程度比較高,針對性比較強,誤傷率低       缺點:得有個會寫相關算法分析的

  以上爲個人看法,通常我們的營銷活動對於這種情況的選擇都是:忽略(滑稽臉,不要扔磚)

 

三、那我們是怎樣確保獎品不會很快被人抽光呢?重點來了,開始集中活力,哦不是注意力~~

  在活動中將整個活動時間換算成秒,然後拿來除以獎品總數量 。比如一天有  (24*60*60s)/(3000個獎品)得到平均兩個獎品發放時間間隔(得到值A),當然平均時間發放容易讓人詬病,做營銷活動的知道,總是能遇到

  死纏爛打的這樣的一些愛佔便宜的和鑽牛角尖的用戶。我們總歸有辦法解決這個問題(廢話)。

  根據活動結束時間和最後一次發獎時間 之差 (得到值B)作爲隨機數種子

  根據已經發放的獎品數量得到完美的情況下理論上需要使用的時間(A*發放的獎品數量,得到值C)

  用活動開始時間+C+隨機時間(使用種子B得到,這樣每個Random第一次Next()得到的值是固定的)得到下個獎品的發放時間 (得到時間D)

  如果當前時間>=時間D   則說明下個獎品應該發放了。即:發放給時間D之後第一個進入抽獎的用戶

  羅哩羅嗦的,說的有點蒙。~~~~~~~~來讓我們看看代碼吧

 

 /// <summary>
    /// 獎項
    /// </summary>
    public interface IAward
    {
        /// <summary>
        /// 獎品編號
        /// </summary>
          int ID { get; set; }
        /// <summary>
        /// 獎品名稱
        /// </summary>
          string  Name { get; set; }
        /// <summary>
        /// 獎品剩餘數量
        /// </summary>
          int SurplusCount { get; set; }
        /// <summary>
        /// 產品總數
        /// </summary>
          int TotalCount { get; set; }
        /// <summary>
        /// 獎品位置
        /// </summary>
          int TurnLocation { get; set; }
        /// <summary>
        /// 商品價格
        /// </summary>
          decimal TurnPrice { get; set; }
        /// <summary>
        /// 最後一次被抽中時間
        /// </summary>
          DateTime LastWinningTime { get; set; }
             
 
    }
View Code

  上邊的代碼是獎品項的接口,用於傳遞給算法和脫離實際的獎品實體。下邊的纔是硬菜


public class DrawPro { public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } DateTime? LastUpdateTime; public List<IAward> AwardsCollection { get; set; } public DrawPro(List<IAward> awardsCollection, DateTime startTime, DateTime endTime ,DateTime lastTime) {this.AwardsCollection = awardsCollection; //獎項集合 this.StartTime = startTime; //活動的開始時間 this.EndTime = endTime; //活動的結束時間 this.LastUpdateTime = lastTime; } /// <summary> /// 從獎項集合中抽取獎品 /// </summary> /// <returns>獎品項</returns> public IAward Draw(bool VaryAward=false) { if (this.AwardsCollection != null && this.AwardsCollection.Count > 0) { return GetWinningAwards(VaryAward); } //抽獎 return null; } /// <summary> /// 從集合中抽取獎品項 /// </summary> protected IAward GetWinningAwards(bool varyAward) { if (AwardsCollection == null) { return null; //沒有傳遞獎品時候,直接返回null } //總是能夠出獎,從所有的獎類中選出一個獎類,獎品餘量越多的,越容易命中 IAward awards = RandomGetAwardBath(this.AwardsCollection); // //獎品發放完畢 if (awards == null) { return null; } if (varyAward) { return awards; } TimeSpan lstspan = StartTime.Subtract(LastUpdateTime.Value); int currentBalance = 0; // awards.SurplusCount; //剩餘獎品數量 int currentAmount = 0; // awards.TotalCount; //獎品總數 foreach (var item in this.AwardsCollection) { currentBalance += item.SurplusCount; currentAmount += item.TotalCount; } TimeSpan tsanSs = EndTime.Subtract(StartTime); long dataTime = Math.Abs((long)tsanSs.TotalMilliseconds / currentAmount); //兩個獎品出獎時間間隔(單位毫秒) if (dataTime == 0) { dataTime = 100;//當時間無法分配的時候,設置默認出獎 } //使用lastUpdateTime 作爲隨機因子保證下一個獎品的出獎時間對每個抽獎者一樣 Random rand = new Random(lstspan.Milliseconds); //計算下一個獎品的釋放時間點 //已經出獎所用時間+ 小於間隔的時間(<dataTime),就是下個獎品的出獎時間 , //用一個隨機數%dataTime的到結果永遠小於dataTime long releaseTime = (currentAmount - currentBalance) * dataTime + rand.Next() % dataTime; DateTime eqTime = this.StartTime.AddMilliseconds(releaseTime); if (DateTime.Now < eqTime) { /*當前時間未達到下一個獎品的釋放時間點*/ return null; } return awards; }
/// <summary> /// 隨機獲取一個獎品(總是出獎) /// </summary> /// <param name="awardBatchs"></param> /// <returns></returns> protected IAward RandomGetAwardBath(List<IAward> awardBatchs) { if (awardBatchs == null || awardBatchs.Count <= 0) { return null; } int weight = 0; for (int i = 0; i < awardBatchs.Count; i++) { weight += awardBatchs[i].SurplusCount; } if (weight == 0) //剩餘獎品數量 { return null; } /*這裏:如果剩餘的獎品數量不變,那麼此處隨機出的結果是不會變化的,即:當獎品數量不變時候,這裏能指定下次出獎的獎品,任何情況下不會改變,除非 獎品數量發生了變化 */ Random random = new Random(weight); int num = random.Next(weight); for (int i = 0; i < awardBatchs.Count; i++) { num -= awardBatchs[i].SurplusCount; //確保num-每個獎品的數量,當小於0時候就可以出獎, 循環內確保總是能夠出獎 if (num < 0) { return awardBatchs[i]; } } return null; } }

請大家看代碼吧,懶得說了,看不明白私信我哦

歡迎拍磚

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章