如何使平均分数计算小于 0.01 秒?



我创建了一个函数来平均TVAndMovie中的评论。但是,当我创建 100000 条评论时,平均需要 4 秒才能获得分数的平均值!我一直在努力找到一种方法来获得分数的平均值。如何将时间减少到0.01秒以下?

class TVAndMovie(models.Model):
tmdb_id = models.IntegerField(
verbose_name="",
blank=False,
null=False,
)

judge_tv_or_movie = models.CharField(
blank=False, null=False, default="movie", max_length=20
)
stars = models.FloatField(
blank=False,
null=False,
default=0,
validators=[MinValueValidator(0.0), MaxValueValidator(10.0)],
)
def get_comments(self) -> object:
return Comment.objects.filter(
tv_or_movie_id=self.id
)
def average_stars(self) -> float:
comments = self.get_comments()
n_comments = comments.count()
if n_comments:
self.stars = round(
sum([comment.stars for comment in comments]) / n_comments, 3
)
else:
self.stars = 0
self.save()
return self.stars
class Comment(models.Model):
comment = models.TextField(max_length=1000)
stars = models.FloatField(
blank=False,
null=False,
default=0,
validators=[MinValueValidator(0.0), MaxValueValidator(10.0)],
)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
tv_or_movie = models.ForeignKey(TVAndMovie, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ("user", "tv_or_movie")
indexes = [models.Index(fields=["user", "tv_or_movie"])]

所以我决定调试你的代码并衡量性能 - 因为我使用更快的计算机(对于 100k 记录,它在不到几秒钟的时间内执行average_stars方法),我创建了500kComments.然后此方法在大约4.5 秒内执行。

我使用调试视图测量了性能:

class IndexView(TemplateView):
def get(self, *args, **kwargs):
tv_or_movie = TVAndMovie.objects.first()
start = time.time()
stars = tv_or_movie.average_stars()
end = time.time()
return JsonResponse({
'finish': end-start,
'rate': stars,
})

然后,我尝试编写优化的代码 - 我决定使用_set指令,然后使用values_list方法将stars值转换为list,而不是调用直接查询。

这样我得到了0.2秒的执行时间(性能)。 法典:

def average_stars(self) -> float:
get_stars = list(self.comment_set.values_list('stars', flat=True))
if get_stars:
self.stars = round(
sum(get_stars) / len(get_stars), 3
)
self.save()
return self.stars

通常使用.count()还不错,但len()更快,您可以在将stars值缓存到所述list时获得的list上执行它。

此外,我认为这是计算平均评级的最快和最简单的方法,您可能不会获得低于0.01s的性能,但我认为这对您来说已经足够了。

如果您有任何问题,请在评论中回复我。

---更新---

我忘了Django也支持Django ORM中的Sum。所以基本上你可以用这个逻辑简单地计算平均值:

def average_stars(self) -> float:
count = self.comment_set.count()
if count:
get_sum = self.comment_set.aggregate(Sum('stars'))
self.stars = round(
get_sum['stars__sum'] / count, 3
)
self.save()
return self.stars

这比执行速度快了两倍,执行时间约为0.1 秒

最新更新