Mercurial > defr > drupal > ad
diff channel/ad_channel.inc @ 7:6aeff3329e01 ad
maj module ad 2.1rc1
author | piotre |
---|---|
date | Mon, 20 Jul 2009 13:54:40 +0000 |
parents | e5584a19768b |
children |
line wrap: on
line diff
--- a/channel/ad_channel.inc Thu May 28 14:53:07 2009 +0000 +++ b/channel/ad_channel.inc Mon Jul 20 13:54:40 2009 +0000 @@ -14,61 +14,73 @@ function ad_channel_cache_filter($ads) { _debug_echo("ad_channel_cache: adserve_cache_filter"); + // get channel array from cache $channels = adserve_cache('get_cache', 'channel'); - $valid = array(); - $nochannel = array(); - $nochannel_weight = array(); - $matched_channel = array(); + // 0 = only display advertisements not assigned to any channel if no matching + // ads in selected channel; 1 = always display advertisements not assigned to + // any channel; 2 = never display advertisements not assigned to any channel + $nochannel_display = $channels['display']; + $valid_ads = array(); + $nochannel_fallback_ads = array(); + $nochannel_percent = array(); + // determine which channels each advertisement is assigned to foreach ($ads as $aid) { _debug_echo("ad_channel_cache: checking aid($aid)"); if (is_array($channels['ads']) && isset($channels['ads'][$aid]) && is_array($channels['ads'][$aid])) { foreach ($channels['ads'][$aid] as $chid) { $channel = $channels['channels'][$chid]; - $display = $channel->display; + $display_by_url = $channel->display; $urls = unserialize($channel->urls); $frontpage = adserve_variable('site_frontpage') ? adserve_variable('site_frontpage') : 'node'; $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote($frontpage, '/') .'\2'), preg_quote($urls, '/')) .')$/'; $match = preg_match($regexp, adserve_variable('url')); - _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match)"); - if ($display == 0) { // display on all except listed urls + _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match) display[$display_by_url]"); + // display ad on all except matching urls + if ($display_by_url == 0) { if (empty($urls) || !$match) { _debug_echo("ad_channel_cache: aid($aid) is valid"); - $valid[] = $aid; - if ($display == 1) { - $nochannel_weight[$chid] = $channel->no_channel_weight; + $valid_ads[$chid][] = $aid; + if ($nochannel_display == 1) { + $nochannel_percent[$chid] = $channel->no_channel_percent; + _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); } - $matched_channel[$aid] = $chid; - _debug_echo("ad_channel_cache: channel($channel->chid) no_channel_weight(". $nochannel_weight[$chid] .')'); + else { + _debug_echo("ad_channel_cache: channel($chid)"); + } break; } } - else { // display only on listed urls + // display ad on matching urls + else { if (!empty($urls) && $match) { _debug_echo("ad_channel_cache: aid($aid) is valid"); - $valid[] = $aid; - if ($display == 1) { - $nochannel_weight[$chid] = $channel->no_channel_weight; + $valid_ads[$chid][] = $aid; + if ($nochannel_display == 1) { + $nochannel_percent[$chid] = $channel->no_channel_percent; + _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); } - $matched_channel[$aid] = $chid; + else { + _debug_echo("ad_channel_cache: channel($chid)"); + } break; } } + // no match so we didn't hit a break, ad is not valid _debug_echo("ad_channel_cache: aid($aid) is not valid"); } } else { - // no channel information for ad, it's valid - $display = $channels['display']; - _debug_echo("ad_channel_cache: aid($aid) has no channel info [$display]"); - switch ($display) { + // no channel information for ad + _debug_echo("ad_channel_cache: aid($aid) has no channel info, nochannel_display($nochannel_display)"); + switch ($nochannel_display) { case 0: - $nochannel[] = $aid; - _debug_echo("ad_channel_cache: aid($aid) is valid if no valid ads found in current channel"); + $nochannel_fallback_ads[] = $aid; + _debug_echo("ad_channel_cache: non-channel aid($aid) is valid if no valid ads are assigned to current channel"); break; case 1: - $valid[] = $aid; - _debug_echo("ad_channel_cache: aid($aid) is valid"); + $valid_ads[0][] = $aid; + _debug_echo("ad_channel_cache: non-channel aid($aid) is valid"); break; case 2: _debug_echo("ad_channel_cache: aid($aid) is not valid"); @@ -77,57 +89,85 @@ } } - // Apply weights, applicable for advertisements that are not assigned to any - // channel. - if (!empty($valid) && !empty($nochannel_weight)) { - $weights = array(); - foreach ($valid as $aid) { - if (isset($matched_channel[$aid])) { - $chid = $matched_channel[$aid]; - if (isset($nochannel_weight[$chid])) { - $weights[$aid] = $nochannel_weight[$chid]; - _debug_echo("ad_channel_cache: ad $aid in channel $chid with weight ". $nochannel_weight[$chid]); + // Apply frequencies, applicable to all channels + if (!empty($valid_ads) && !empty($nochannel_percent)) { + $frequencies = array(); + foreach (array_keys($valid_ads) as $chid) { + if ($chid) { + if (isset($nochannel_percent[$chid]) && $nochannel_percent[$chid]) { + $frequencies[$chid] = $nochannel_percent[$chid]; + _debug_echo("ad_channel_cache: channel $chid has a non-channel ad frequency of ". $nochannel_percent[$chid]."%"); } else { - // by default, ads are assigned a weight of 100% - $weights[$aid] = 100; - _debug_echo("ad_channel_cache: ad $aid in channel $chid with default weight of 100"); + // by default, channels return 'non-channel ads' with a frequency + // of 10% + $frequencies[$chid] = 10; + _debug_echo("ad_channel_cache: channel $chid assigned a default non-channel ad frequency of 10%"); } } else { - // by default, ads are assigned a weight of 100% - $weights[$aid] = 100; - _debug_echo("ad_channel_cache: ad $aid in no channel with default weight of 100"); + // frequency for non-channel ads is not meaningful } } - if (!empty($weights)) { - $gcd = ad_channel_probability_gcd($weights); - $display = array(); - _debug_echo("ad_channel_cache: adjusting channel weights, gcd ($gcd)"); - foreach ($valid as $aid) { - $weight = $weights[$aid] / $gcd; - for ($i = 1; $i <= $weight; $i++) { - $display[] = $aid; + if (!empty($frequencies)) { + $balanced_channels = array(); + $num_channels = sizeof($valid_ads); + + foreach (array_keys($valid_ads) as $chid) { + if (isset($frequencies[$chid])) { + // for a given channel, ensure the proper ratio to non-channel ads + if ($frequencies[$chid] <= 50) { // increase occurrences of $chid + $balanced_channels[] = 0; + $frequency = round(100 / $frequencies[$chid]) - 1; + _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to $frequency:1 relative non-channel ads"); + for ($i = 1; $i <= $frequency; $i++) { + $balanced_channels[] = $chid; + } + } + else { // add $chid and additional non-channel ads + $balanced_channels[] = $chid; + $frequency = round(100 / (100 - $frequencies[$chid])) - 1; + _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to 1:$frequency relative non-channel ads"); + for ($i = 1; $i <= $frequency; $i++) { + $balanced_channels[] = 0; + } + } } } - $valid = $display; + _debug_echo('ad_channel_cache: channel 0 contains all non-channel ads'); + if (adserve_variable('debug') >= 2) { + foreach ($balanced_channels as $key => $chid) { + _debug_echo("ad_channel_cache: channel $chid => index $key"); + } + } } + $random_channel = _select_channel_id($balanced_channels); } - else if (empty($valid) && !empty($nochannel)) { + else if (!empty($valid_ads)) { + foreach ($valid_ads as $chid => $ads) { + $chids[$chid] = $chid; + } + shuffle($chids); + $random_channel = array_pop($chids); + } + else if (empty($valid_ads) && !empty($nochannel_fallback_ads)) { _debug_echo("ad_channel_cache: using ads with no channel info"); - $valid = $nochannel; + $valid_ads[0] = $nochannel_fallback_ads; + $random_channel = 0; } $premiere = adserve_cache('get_cache', 'premiere'); - $premieres = array(); if (is_array($premiere)) { - foreach ($valid as $aid) { - if (in_array($aid, $premiere)) { - _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement"); - $premieres[$aid] = $aid; - } - else { - _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement"); + $premieres = array(); + foreach (array_keys($valid_ads) as $chid) { + foreach ($valid_ads[$chid] as $aid) { + if (in_array($aid, $premiere)) { + _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement"); + $premieres[$aid] = $aid; + } + else { + _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement"); + } } } if (!empty($premieres)) { @@ -135,31 +175,65 @@ return $premieres; } } - _debug_echo("ad_channel_cache: returning non-premiere advertisements"); - return $valid; + _debug_echo("ad_channel_cache: returning non-premiere advertisements from randomly selected channel $random_channel"); + + if (isset($valid_ads[$random_channel])) { + return ad_channel_enforce_inventory_level($random_channel, $valid_ads[$random_channel]); + } } /** - * Returns the greatest common divisor of an array of integers. + * Randomly select a valid channel id from an array channel ids + * @param array, valid array. */ -function ad_channel_probability_gcd($integers) { - $gcd = array_shift($integers); +function _select_channel_id($choices) { + $selected = 0; + if (is_array($choices)) { + $available = sizeof($choices); + _debug_echo("ad_channel_cache: randomly selecting from $available indexes."); + $selected = $available > 1 ? $choices[mt_rand(0, $available - 1)] : $choices[0]; + _debug_echo("ad_channel_cache: randomly selected channel $selected."); + } - while (!empty($integers)) { - $gcd = _ad_channel_probability_gcd($gcd, array_shift($integers)); - } - return $gcd; + return $selected; } -/** - * Helper function to calculate the greatest common divisor using the Euclidean - * algorithm (http://en.wikipedia.org/wiki/Euclidean_algorithm). +/* + * Augment the selected channel with 'remnant' ads to ensure that any specified + * inventory level is honored + * @param int, channel id + * @param array, valid array. */ -function _ad_channel_probability_gcd($a, $b) { - if ($b == 0) { - return $a; +function ad_channel_enforce_inventory_level($chid, $ads) { + if ($chid > 0) { + $channels = adserve_cache('get_cache', 'channel'); + $channel = $channels['channels'][$chid]; + $level = $channel->inventory; + $num_ads = count($ads); + if ($num_ads < $level) { + _debug_echo("ad_channel_enforce_inventory_level: channel($chid) has $num_ads and needs $level"); + $remnants = array_values(adserve_cache('get_cache', 'remnant')); + $available = count($remnants); + if ($available > 0) { + _debug_echo("ad_channel_enforce_inventory_level: randomly selecting from $available remnants."); + while (count($ads) < $level) { + shuffle($remnants); + $selected = array_pop($remnants); + _debug_echo("ad_channel_enforce_inventory_level: selected $selected."); + $ads[] = $selected; + } + } + else { + _debug_echo("ad_channel_enforce_inventory_level: no remnants to choose from."); + } + } + else { + _debug_echo("ad_channel_enforce_inventory_level: channel($chid) no inventory level assigned"); + } } else { - return _ad_channel_probability_gcd($b, $a % $b); + _debug_echo("ad_channel_enforce_inventory_level: not needed for channel($chid)"); } + return $ads; } +