def test_event(self): # Test event add. for i in range(300): yield db_utils.update_event({ "event_id": str(i), "event_type": stats_consts.EVENT_TYPE_CLICK, "timestamp": 0, "user_id": str(i % 20), "banner_id": '1', "campaign_id": "campaign_id", "event_value": 10, "our_keywords": {}, "human_score": 1 }) # Test event select. counter = 0 event_iter = yield db_utils.get_events_per_user_iter( campaign_id="campaign_id", timestamp=0, uid=u'0') while True: event_doc = yield event_iter.next() if not event_doc: break self.assertEqual(event_doc['user_id'], u'0') self.assertEqual(event_doc['timestamp'], 0) self.assertEqual(event_doc['campaign_id'], "campaign_id") counter += 1 self.assertEqual(counter, 15) unique_uids = yield db_utils.get_distinct_users_from_events( "campaign_id", timestamp=0) self.assertEqual(set(unique_uids), set([str(x) for x in range(20)])) # Test event deletion. for i in range(300): yield db_utils.delete_event(str(i)) counter = 0 event_iter = yield db_utils.get_events_per_user_iter("campaign_id", timestamp=0, uid=u'0') while True: event_doc = yield event_iter.next() if not event_doc: break counter += 1 self.assertEqual(counter, 0)
def create_user_budget(campaign_doc, timestamp, uid): """ Calculate individual user budgets. User budget dictionary default values for each event type are: { 'default_value': 0.0, # Default value for this event type 'event_value': 0.0, # Calculated event value (used later on) 'num': 0, # Number of events of this time in the time period 'share': 0.0 # Share of this user for this event type in the time period } :param campaign_doc: Campaign document :param timestamp: Timestamp (last hour) :param uid: :return: User budget dictionary """ logger = logging.getLogger(__name__) user_budget = defaultdict( lambda: dict(default_value=0, event_value=0.0, num=0, share=0.0)) if campaign_doc is None: defer.returnValue(user_budget) user_events_iter = yield db_utils.get_events_per_user_iter( campaign_doc['campaign_id'], timestamp, uid) while True: event_doc = yield user_events_iter.next() if not event_doc: break event_type = event_doc['event_type'] banner_doc = yield db_utils.get_banner(event_doc['banner_id']) if not filter_event( event_doc, campaign_doc, banner_doc) and event_type in stats_consts.PAID_EVENT_TYPES: user_budget[event_type]['num'] += 1 user_budget[event_type][ 'default_value'] += get_default_event_payment( event_doc, campaign_doc['max_cpc'], campaign_doc['max_cpm']) else: logger.warning('Event type for event_id: ' + event_doc['event_id'] + ' not included in payment calculation.') for event_type in stats_consts.PAID_EVENT_TYPES: if user_budget[event_type]['num'] > 0: user_budget[event_type]['default_value'] /= user_budget[ event_type]['num'] yield logger.debug(user_budget) defer.returnValue(user_budget)
def get_best_user_payments_and_humanity(campaign_doc, timestamp, uid): """ Return user information: best payment, total payment and max human score. :param campaign_doc: :param timestamp: :param uid: :return: Tuple: max_user_payment, max_human_score, total_user_payments """ logger = logging.getLogger(__name__) max_user_payment, max_human_score = 0.0, 0.0 total_user_payments = defaultdict(lambda: float(0.0)) user_value_doc = yield db_utils.get_user_value_in_campaign( campaign_doc['campaign_id'], uid) if user_value_doc: max_user_payment = float(user_value_doc['payment']) user_events_iter = yield db_utils.get_events_per_user_iter( campaign_doc['campaign_id'], timestamp, uid) while True: event_doc = yield user_events_iter.next() if not event_doc: break event_type = event_doc['event_type'] banner_doc = yield db_utils.get_banner(event_doc['banner_id']) if not stats_utils.filter_event( event_doc, campaign_doc, banner_doc) and event_type in stats_consts.PAID_EVENT_TYPES: event_payment = stats_utils.get_default_event_payment( event_doc, campaign_doc['max_cpc'], campaign_doc['max_cpm']) total_user_payments[event_type] += float(event_payment) max_user_payment = max([max_user_payment, event_payment]) max_human_score = max([max_human_score, event_doc['human_score']]) yield logger.info( "User {0} max_user_payment, max_human_score, total_user_payments: {1}". format(uid, (max_user_payment, max_human_score, total_user_payments))) defer.returnValue((max_user_payment, max_human_score, total_user_payments))
def calculate_payments_for_new_users(campaign_doc, timestamp): """ Calculate payments for new uses. Use CPM as default payment. :param campaign_doc: :param timestamp: :return: """ logger = logging.getLogger(__name__) yield logger.info("Calculating payment score for new user.") # For new users add payments as cpv uids = yield db_utils.get_distinct_users_from_events( campaign_doc['campaign_id'], timestamp) yield logger.debug("Found {0} distinct user ids".format(len(uids))) for uid in uids: max_human_score = 0 user_events_iter = yield db_utils.get_events_per_user_iter( campaign_doc['campaign_id'], timestamp, uid) while True: event_doc = yield user_events_iter.next() if not event_doc: break banner_doc = yield db_utils.get_banner(event_doc['banner_id']) if not stats_utils.filter_event(event_doc, campaign_doc, banner_doc): max_human_score = max( [max_human_score, event_doc['human_score']]) user_value_doc = yield db_utils.get_user_value_in_campaign( campaign_doc['campaign_id'], uid) if user_value_doc is None or user_value_doc['payment'] <= campaign_doc[ 'max_cpm']: yield logger.info("Updating user value for {0}".format(uid)) yield db_utils.update_user_value_in_campaign( campaign_doc['campaign_id'], uid, campaign_doc['max_cpm'], max_human_score)
def update_events_payments(campaign_doc, timestamp, uid, user_budget): """ Update or create event payments in the database by dividing user budget among events. :param campaign_doc: Campaign document :param timestamp: Timestamp for the time period of calculation :param uid: User identifier :param user_budget: User budget :return: """ logger = logging.getLogger(__name__) # Get all events for chosen campaign within chosen time period for a chosen user user_events_iter = yield db_utils.get_events_per_user_iter( campaign_doc['campaign_id'], timestamp, uid) while True: event_doc = yield user_events_iter.next() if event_doc is None: break event_type = event_doc['event_type'] banner_doc = yield db_utils.get_banner(event_doc['banner_id']) payment_reason = filter_event(event_doc, campaign_doc, banner_doc) # Pay when not rejected if not payment_reason and event_type in stats_consts.PAID_EVENT_TYPES: event_value = int(user_budget[event_type]['event_value']) else: event_value = 0 # Save to database yield db_utils.update_event_payment(campaign_doc['campaign_id'], timestamp, event_doc['event_id'], event_value, payment_reason) yield logger.debug("New payment ({0}, {1}): {2}, {3}. {4}, {5}".format( campaign_doc['campaign_id'], timestamp, event_doc['event_id'], event_type, event_value, payment_reason))