123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- package addata
- import (
- "fmt"
- "math/rand"
- "miads/adslib/redis_data"
- "miads/adslib/utils"
- "strconv"
- "strings"
- "time"
- )
- type CustomAdData struct {
- Duration int64 `json:"duration"`
- ImageURL string `json:"image_url"`
- JsOrderID string `json:"js_order_id"`
- Msg int64 `json:"msg"`
- OrderName string `json:"order_name"`
- Result int64 `json:"result"`
- Target string `json:"target"`
- TargetAddition []interface{} `json:"target_addition"`
- UserAgent string `json:"user_agent"`
- VideoURL string `json:"video_url"`
- }
- func CombineOrderBy(adData *AdData, dsp *utils.DspParam) {
- ads_item, extra_item = yield get_ads_infos(dsp, order_type = 1)
- if extra_item == None:
- raise
- gen.Return(infos)
- last_target_addition = infos.get('target_addition', [])
- extra_item_addition = extra_item.get('target_addition', [])
- if len(extra_item_addition) == 0:
- raise
- gen.Return(infos)
- if len(extra_item_addition) == 1:
- last_target_addition[0]['urls'].extend(extra_item_addition[0]['urls'])
- raise
- gen.Return(infos)
- else:
- last_target_addition[0]['urls'].extend(extra_item_addition[0]['urls'])
- last_target_addition[1]['urls'].extend(extra_item_addition[1]['urls'])
- infos['target'] = extra_item['target']
- infos['js_order_id'] = extra_item['js_order_id']
- last_target_addition[1]['type'] = 'CLICK'
- raise
- gen.Return(infos)
- }
- // 获取一个广告
- func getOneAds(dsp *utils.DspParam, orderType int, fixFlag int) (*redis_data.AdOrderInfo, error){
- // 取出广告
- orders, err := redis_data.GetOrderInfos(dsp, fixFlag)
- if err != nil {
- return nil, err
- }
- if len(orders) == 0 {
- return nil, nil
- }
- gotOrders := make([]redis_data.AdOrderInfo, 0, 1000)
- allKpi := int64(0)
- for _, order := range orders {
- if order.OrderType == int64(orderType) {
- gotOrders = append(gotOrders, order)
- allKpi += order.ShowKpi
- }
- }
- orderRange := make([]int, 0, 1000)
- curRateIdx := 0
- // orderRange中记录的是当前同索引位置的gotOrders里的order的比例上限, 比如如果有两个order [ShowKpi:40, ShowKpi: 60]
- // 那么orderRange就是 [rate:400, rate: 1000], 所以要按比例取order, 只需要获得在比例上限里随机取一个数, 然后判断落在那个orderRange里,
- // 对应去gotOrders取同索引里的order即可, 因为算法里有对小于1的比例做补偿, 所以rate上限可能超出1000, rate乘1000而不是100主要是为了
- // 如果showKpi差异过大, 对大量小于1的订单做补偿, 会影响整体流量分布, 这里放到1000倍, 降低补偿1的影响, 算法复杂度是O(n), 只有三个非嵌套循环
- for _, order := range gotOrders {
- rate := int(float32(order.ShowKpi) / float32(allKpi) * 1000)
- // 防止比例过小, 取int后变为0
- if rate < 1 {
- rate = 1
- }
- curRateIdx = curRateIdx + rate
- orderRange = append(orderRange, curRateIdx)
- }
- randNum := rand.Intn(curRateIdx)
- for i, rateRange := range orderRange {
- if randNum <= rateRange {
- return &gotOrders[i], nil
- }
- }
- return nil, nil
- }
- // 获取投放数量
- func getNeedDispatchCount(adData *redis_data.AdOrderInfo) (int,error) {
- beginTime := time.Unix(adData.BeginTime, 0)
- // 获取当前分钟值
- beginMinute := beginTime.Minute() + (beginTime.Hour() * 60)
- // 获取起点分钟, 不知道原因, 不加会有bug
- beginMinute += 2
- // 获取分钟数到24点还能跑多少值
- key := "time_all_count_" + strconv.Itoa(beginMinute)
- // 0 默认曲线, 1 定制曲线
- if adData.LineType == 1 {
- key = fmt.Sprintf("time_all_count_%d_%d", adData.OrderID, beginMinute)
- }
- // 起始剩余值
- beginRemainDispatchCount, err := redis_data.GetRemainDispatchCount(key)
- if err != nil {
- return 0, err
- }
- // 计算最后分钟
- endTime := time.Unix(adData.EndTime, 0)
- endMinute := endTime.Minute() + (endTime.Hour() * 60)
- if endMinute > 1439 {
- // 不懂这里逻辑
- endMinute = endMinute - 1440 + 2
- }
- key = "time_all_count_" + strconv.Itoa(endMinute)
- if adData.LineType == 1 {
- // 定制曲线
- key = fmt.Sprintf("time_all_count_%d_%d", adData.OrderID, endMinute)
- }
- endRemainDispatchCnt, err := redis_data.GetRemainDispatchCount(key)
- if err != nil {
- return 0, err
- }
- // 结束的剩余值 - 起始剩余值 = 获取区间能跑的值
- needDispatchCount := beginRemainDispatchCount - endRemainDispatchCnt
- return needDispatchCount, nil
- }
- func GetAdsInfos(dsp *utils.DspParam, advertiser string, orderType int, fixFlag int, xiaomiHasFlag int) {
- ua = dsp.ua_client
- req_source = dsp.req_source
- order, err := getOneAds(dsp, order_type, fix_flag)
- if err != nil {
- return err
- }
- if order == nil {
- return nil
- }
- r = rand.Intn( 100)
- if xiaomiHasFlag == 1 {
- if strings.Index(order.Title, "_ios") > 0 {
- return nil
- } else {
- r = rand.Intn(50)
- }
- }
- // 获取剩余时间内的值
- needDispatchCnt, err := getNeedDispatchCount(order)
- if err != nil {
- return err
- }
- if needDispatchCnt < 1 {
- return nil, nil
- }
- curTime := time.Now()
- // #已经投放的key
- finishShowCnt, err := redis_data.GetFinishedDispatchCount(order.OrderID, "show", curTime)
- if err != nil {
- return nil, err
- }
- finishClickCnt, err := redis_data.GetFinishedDispatchCount(order.OrderID, "click", curTime)
- if err != nil {
- return nil, err
- }
- redis_data.SetPlanDispatchCount(order.OrderID, "show", needDispatchCount, time.Now().Unix())
- // 计算曲线比例
- rate := float32(order.ShowKpi) / float32(needDispatchCnt)
- curMinutes := curTime.Hour() * 60 + curTime.Minute()
- key := "time_" + strconv.Itoa(curMinutes)
- if order.LineType == 1 {
- // 定制曲线
- key = fmt.Sprintf("time_%d_%d", order.OrderID, curMinutes)
- }
- lineValue, err := redis_data.GetPerMinuteNeedDispatchCnt(order.OrderID, curTime)
- if err != nil {
- return nil, err
- }
- // 当前分钟需要放出去的数量
- curMinuteNeedDispatchCnt := int(float32(lineValue) * rate)
- if dispatchCnt < 1 {
- dispatchCnt = 1
- }
- redis_data.SetOrderPlanDispatchCount(order.OrderID, "show", dispatchCnt, curTime)
- // 获取当前分钟已经完成的下发
- curMinutefinishedDispatchCnt, err := redis_data.GetPreMinuteFinishedDispatchCount(order.OrderID, "show", curTime)
- if curMinutefinishedDispatchCnt < curMinuteNeedDispatchCnt {
- data =
- {
- "js_order_id":js_order_id,
- "target":"",
- "video_url":"",
- "duration":5,
- "target_addition":[],
- "image_url":"",
- "result":0,
- "msg":0,
- "user_agent":ua,
- "order_name":order_name
- }
- //放量
- newFinishCnt, err := redis_data.IncrFinishedDispatchCount(order.OrderID, "show", 1, curTime)
- if err != nil {
- return err
- }
- newCurMinutefinishedCnt, err := redis_data.IncrPreMinuteFinishedDispatchCount(order.OrderID, "show", 1, curTime)
- if err != nil {
- return err
- }
- show_url = ads_item['show_url']
- click_url = ads_item['click_url']
- target = ads_item['target_url']
- if strings.Index(order.Title, "_ios") != -1 {
- iosImei, iosUa, err := redis_data.GetIosUaImei(dsp.Ip)
- if err != nil {
- return err
- }
- if iosUa {
- }
- data['user_agent'] = ios_ua
- if ads_item.get('imei_replace_flag', 0) == 1 and
- ios_imei:
- show_url = show_url.replace('__IDFA__', ios_imei)
- click_url = click_url.replace('__IDFA__', ios_imei)
- target = target.replace('__IDFA__', ios_imei)
- if order_name.find("__OS__") > 0:
- show_url = show_url.replace('__OS__', '1')
- click_url = click_url.replace('__OS__', '1')
- target = target.replace('__OS__', '1')
- }
- elif
- order_name.find("_android") > 0 :
- ### 判断是否需要替换imei
- if ads_item.get('imei_replace_flag', 0) == 1:
- show_url = show_url.replace('__IMEI__', dsp.real_md5_imei)
- click_url = click_url.replace('__IMEI__', dsp.real_md5_imei)
- target = target.replace('__IMEI__', dsp.real_md5_imei)
- if order_name.find("__OS__") > 0:
- show_url = show_url.replace('__OS__', '0')
- click_url = click_url.replace('__OS__', '0')
- target = target.replace('__OS__', '0')
- else:
- if r < 40:
- ios_imei, ios_ua = get_ios_ua_imei(dsp)
- if ios_ua:
- data['user_agent'] = ios_ua
- if ads_item.get('imei_replace_flag', 0) == 1 and
- ios_imei:
- show_url = show_url.replace('__IDFA__', ios_imei)
- click_url = click_url.replace('__IDFA__', ios_imei)
- target = target.replace('__IDFA__', ios_imei)
- if order_name.find("__OS__") > 0:
- show_url = show_url.replace('__OS__', '1')
- click_url = click_url.replace('__OS__', '1')
- target = target.replace('__OS__', '1')
- else:
- if ads_item.get('imei_replace_flag', 0) == 1:
- show_url = show_url.replace('__IMEI__', dsp.real_md5_imei)
- click_url = click_url.replace('__IMEI__', dsp.real_md5_imei)
- target = target.replace('__IMEI__', dsp.real_md5_imei)
- if order_name.find("__OS__") > 0:
- show_url = show_url.replace('__OS__', '0')
- click_url = click_url.replace('__OS__', '0')
- target = target.replace('__OS__', '0')
- if order_name.find("__IP__") > 0:
- show_url = show_url.replace('__IP__', dsp.ip)
- click_url = click_url.replace('__IP__', dsp.ip)
- target = target.replace('__IP__', dsp.ip)
- if order_type == 0:
- addi = get_monitor_url('VIEW', 5, order_name, req_source, show_url)
- else:
- addi = get_monitor_url('VIEW', 5, order_name, 'follow', show_url)
- #addi['urls'].append(show_url)
- data['target_addition'].append(addi)
- r = random.randint(0, 1000)
- c_rate = click_kpi * 1.0 / (ads_item['show_kpi']) * 1000
- if r < c_rate:
- #下发点击
- addi = get_monitor_url('CLICK', 1, order_name, req_source, click_url)
- #addi['urls'].append(click_url)
- data['target_addition'].append(addi)
- md5_skip = hashlib.md5(target).hexdigest()
- redis_tools.incr_key_value(click_key)
- real_target = ads_config.Host + "?action=LOADING&req_source={0}&advertiser={2}&skip={1}&skip_other={3}".format(
- req_source, '', order_name, md5_skip)
- ### 塞入缓存中
- redis_tools.set_skip_info(md5_skip, target)
- data['target'] = real_target
- raise
- gen.Return((None, data))
- }
- #获取当前已经放出去的次数
- raise gen.Return((None, None))
- }~
|