addons-server/apps/reviews/tasks.py

89 строки
3.1 KiB
Python

import logging
from django.db.models import Count, Avg, F
import caching.base as caching
from celeryutils import task
from addons.models import Addon
from .models import Review, GroupedRating
log = logging.getLogger('z.task')
@task(rate_limit='50/m')
def update_denorm(*pairs, **kw):
"""
Takes a bunch of (addon, user) pairs and sets the denormalized fields for
all reviews matching that pair.
"""
log.info('[%s@%s] Updating review denorms.' %
(len(pairs), update_denorm.rate_limit))
using = kw.get('using')
for addon, user in pairs:
reviews = list(Review.objects.valid().no_cache().using(using)
.filter(addon=addon, user=user).order_by('created'))
if not reviews:
continue
for idx, review in enumerate(reviews):
review.previous_count = idx
review.is_latest = False
reviews[-1].is_latest = True
for review in reviews:
review.save()
@task
def addon_review_aggregates(*addons, **kw):
log.info('[%s@%s] Updating total reviews.' %
(len(addons), addon_review_aggregates.rate_limit))
using = kw.get('using')
stats = dict(Review.objects.latest().filter(addon__in=addons)
.using(using).values_list('addon').annotate(Count('addon')))
for addon in addons:
count = stats.get(addon, 0)
Addon.objects.filter(id=addon).update(total_reviews=count)
log.info('[%s@%s] Updating average ratings.' %
(len(addons), addon_review_aggregates.rate_limit))
stats = dict(Review.objects.valid().filter(addon__in=addons)
.using(using).values_list('addon').annotate(Avg('rating')))
for addon in addons:
avg = stats.get(addon, 0)
Addon.objects.filter(id=addon).update(average_rating=avg)
# Delay bayesian calculations to avoid slave lag.
addon_bayesian_rating.apply_async(args=addons, countdown=5)
addon_grouped_rating.apply_async(args=addons, kwargs={'using': using})
@task
def addon_bayesian_rating(*addons, **kw):
log.info('[%s@%s] Updating bayesian ratings.' %
(len(addons), addon_bayesian_rating.rate_limit))
f = lambda: Addon.objects.aggregate(rating=Avg('average_rating'),
reviews=Avg('total_reviews'))
avg = caching.cached(f, 'task.bayes.avg', 60 * 60 * 60)
mc = avg['reviews'] * avg['rating']
for addon in Addon.uncached.filter(id__in=addons):
q = Addon.objects.filter(id=addon.id)
if addon.total_reviews:
num = mc + F('total_reviews') * F('average_rating')
denom = avg['reviews'] + F('total_reviews')
q.update(bayesian_rating=num / denom)
else:
q.update(bayesian_rating=0)
@task
def addon_grouped_rating(*addons, **kw):
"""Roll up add-on ratings for the bar chart."""
# We stick this all in memcached since it's not critical.
log.info('[%s@%s] Updating addon grouped ratings.' %
(len(addons), addon_grouped_rating.rate_limit))
using = kw.get('using')
for addon in addons:
GroupedRating.set(addon, using=using)