Skip to content

Commit

Permalink
Build an aggregation for ad rotations
Browse files Browse the repository at this point in the history
  • Loading branch information
davidfischer committed Oct 18, 2024
1 parent abdb7a2 commit aa68d48
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
6 changes: 6 additions & 0 deletions adserver/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from .models import Region
from .models import RegionImpression
from .models import RegionTopicImpression
from .models import RotationImpression
from .models import Topic
from .models import UpliftImpression
from .models import View
Expand Down Expand Up @@ -879,6 +880,11 @@ class UpliftImpressionAdmin(ImpressionsAdmin):
pass


@admin.register(RotationImpression)
class RotationImpressionAdmin(ImpressionsAdmin):
date_hierarchy = "date"


class PlacementImpressionAdmin(ImpressionsAdmin):
readonly_fields = ("div_id", "ad_type_slug") + ImpressionsAdmin.readonly_fields
list_display = ("div_id", "ad_type_slug") + ImpressionsAdmin.list_display
Expand Down
34 changes: 34 additions & 0 deletions adserver/migrations/0098_rotation_aggregation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 5.0.9 on 2024-10-18 18:03

import django.db.models.deletion
import django_extensions.db.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('adserver', '0097_migrate_jsonfield'),
]

operations = [
migrations.CreateModel(
name='RotationImpression',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')),
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')),
('date', models.DateField(db_index=True, verbose_name='Date')),
('decisions', models.PositiveIntegerField(default=0, help_text="The number of times the Ad Decision API was called. The server might not respond with an ad if there isn't inventory.", verbose_name='Decisions')),
('offers', models.PositiveIntegerField(default=0, help_text='The number of times an ad was proposed by the ad server. The client may not load the ad (a view) for a variety of reasons ', verbose_name='Offers')),
('views', models.PositiveIntegerField(default=0, help_text='Number of times the ad was legitimately viewed', verbose_name='Views')),
('clicks', models.PositiveIntegerField(default=0, help_text='Number of times the ad was legitimately clicked', verbose_name='Clicks')),
('advertisement', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='rotated_impressions', to='adserver.advertisement')),
('publisher', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='rotated_impressions', to='adserver.publisher')),
],
options={
'ordering': ('-date',),
'unique_together': {('publisher', 'advertisement', 'date')},
},
),
]
27 changes: 27 additions & 0 deletions adserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,33 @@ def __str__(self):
return "Uplift of %s on %s" % (self.advertisement, self.date)


class RotationImpression(BaseImpression):
"""
Create an index of ads that were rotated.
Indexed one per ad/publisher per day.
This is a subset of AdImpressions. Only rotated ads (rotations > 1) are counted.
"""

publisher = models.ForeignKey(
Publisher, related_name="rotated_impressions", on_delete=models.PROTECT
)
advertisement = models.ForeignKey(
Advertisement,
related_name="rotated_impressions",
on_delete=models.PROTECT,
null=True,
)

class Meta:
ordering = ("-date",)
unique_together = ("publisher", "advertisement", "date")

def __str__(self):
"""Simple override."""
return "Rotations of %s on %s" % (self.advertisement, self.date)


class RegionTopicImpression(BaseImpression):
"""
Create an index combining aggregated keywords & geos.
Expand Down
52 changes: 52 additions & 0 deletions adserver/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from .models import Region
from .models import RegionImpression
from .models import RegionTopicImpression
from .models import RotationImpression
from .models import Topic
from .models import UpliftImpression
from .reports import PublisherReport
Expand Down Expand Up @@ -508,6 +509,56 @@ def daily_update_uplift(day=None):
)


@app.task()
def daily_update_rotations(day=None):
"""
Generate the daily index of RotationImpressions.
:arg day: An optional datetime object representing a day
"""
start_date, end_date = get_day(day)

log.info("Updating rotation data for %s-%s", start_date, end_date)

queryset = Offer.objects.using(settings.REPLICA_SLUG).filter(
date__gte=start_date,
date__lt=end_date, # Things at UTC midnight should count towards tomorrow
)

for values in (
queryset.values("publisher", "advertisement")
.filter(rotations__gt=1)
.annotate(
total_decisions=Count("publisher"),
total_offers=Count("publisher", filter=Q(advertisement__isnull=False)),
total_views=Count("publisher", filter=Q(viewed=True)),
total_clicks=Count("publisher", filter=Q(clicked=True)),
)
.filter(total_decisions__gt=0)
.order_by("-total_decisions")
.values(
"publisher",
"advertisement",
"total_decisions",
"total_offers",
"total_views",
"total_clicks",
)
.iterator()
):
impression, _ = RotationImpression.objects.using("default").get_or_create(
publisher_id=values["publisher"],
advertisement_id=values["advertisement"],
date=start_date,
)
RotationImpression.objects.using("default").filter(pk=impression.pk).update(
decisions=values["total_decisions"],
offers=values["total_offers"],
views=values["total_views"],
clicks=values["total_clicks"],
)


@app.task()
def daily_update_advertisers(day=None):
"""
Expand Down Expand Up @@ -647,6 +698,7 @@ def update_previous_day_reports(day=None):
daily_update_publishers(start_date) # Important: after daily_update_impressions
daily_update_keywords(start_date)
daily_update_uplift(start_date)
daily_update_rotations(start_date)
daily_update_regiontopic(start_date)

# Updates an aggregation on each paid flight
Expand Down

0 comments on commit aa68d48

Please sign in to comment.