агрегация django в более низкое разрешение с использованием группировки по диапазону дат - PullRequest
5 голосов
/ 07 июня 2011

ужасный заголовок, но позвольте мне объяснить: у меня есть эта модель django, содержащая метку времени (дата) и атрибут log - f.e. количество пользователей, потребляющих какой-либо ресурс - (значение).

class Viewers(models.Model):
    date = models.DateTimeField()
    value = models.IntegerField()

за каждые 10 секунд таблица содержит количество пользователей. как то так:

| date | value |
|------|-------|
|  t1  |   15  |
|  t2  |   18  |
|  t3  |   27  |
|  t4  |   25  |
|  ..  |   ..  |
|  t30 |   38  |
|  t31 |   36  |
|  ..  |   ..  |

Теперь я хочу создать различную статистику из этих данных, каждая с другим разрешением. F.E. для графика последнего дня мне не нужно разрешение 10 секунд, поэтому я хочу 5-минутные шаги (которые строятся путем усреднения значений (и, возможно, также)) строк от t1 до t29, от t30 до t59,. ..), так что я получу:

| date | value |
|------|-------|
|  t15 |   21  |
|  t45 |   32  |
|  ..  |   ..  |

атрибуты для хранения переменной - это отметка времени начала и конца и разрешение (например, 5 минут). Есть ли способ с помощью API django Orm / queryset и, если нет, как достичь этого с помощью пользовательских SQL?

Ответы [ 4 ]

3 голосов
/ 13 февраля 2014

Я пытался решить эту проблему самым «джанго» способом.Я согласился на следующее.Он усредняет значения для 15-минутных временных интервалов между start_date и end_date, где имя столбца is'date ':

readings = Reading.objects.filter(date__range=(start_date, end_date)) \
   .extra(select={'date_slice': "FLOOR (EXTRACT (EPOCH FROM date) / '900' )"}) \
   .values('date_slice') \
   .annotate(value_avg=Avg('value'))

Возвращает словарь:

 {'value_avg': 1116.4925373134329, 'date_slice': 1546512.0}
 {'value_avg': 1001.2028985507246, 'date_slice': 1546513.0}
 {'value_avg': 1180.6285714285714, 'date_slice': 1546514.0}

Суть идеи приходитиз этого ответа на тот же вопрос для PHP / SQL.Код, переданный в extra, предназначен для БД Postgres.

2 голосов
/ 07 июня 2011
from django.db.models import Avg

Viewers.objects.filter(date__range=(start_time, end_time)).aggregate(average=Avg('value'))

Это даст вам среднее значение по всем values между start_time и end_time, возвращаемым в виде словаря в виде { 'average': <the average> }.

start_time и end_time должны быть объектами даты и времени Python.Поэтому, если у вас есть временная метка или что-то еще, вам сначала нужно ее преобразовать.Вы также можете использовать datetime.timedelta для вычисления end_time на основе времени начала.Для пятиминутного разрешения, что-то вроде этого:

from datetime import timedelta

end_time = start_time + timedelta(minutes=5)
1 голос
/ 07 июня 2011

Вы смотрели на диапазон фильтр?

https://docs.djangoproject.com/en/dev/ref/models/querysets/#range

Пример, приведенный в документе, похоже на вашу ситуацию.

0 голосов
/ 08 июня 2011

После долгих попыток я сделал это как SQL-оператор:

SELECT FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(date))), SUM(value)
FROM `my_table`
WHERE date BETWEEN SUBTIME(NOW( ), '0:30:00') AND NOW()
GROUP BY UNIX_TIMESTAMP(date) DIV 300
ORDER BY date DESC

с

start_time = SUBTIME(NOW( ), '0:30:00')
end_time = NOW()
period = 300 # in seconds

в конце - не очень сложно - и действительно не зависит от временного разрешениявыборки в исходной таблице.

...