Цель
Я пытаюсь сократить объем данных, отправляемых на внешний интерфейс приложения, путем выборки временных рядов. Первоначально, просто взяв каждую n-ю строку, потому что я также хочу оптимизировать скорость.
Макет
Я использую Django 2.1.5, с PostgreSQL бэкэнд. Таблица временных рядов заполняется данными измерений каждые 1-15 минут от различных датчиков.
models.py
class Measurement(models.Model):
sensor = models.ForeignKey(Category,on_delete=models.PROTECT,related_name='measurements')
datapoint = models.DecimalField(max_digits=8, decimal_places=4)
time = models.DateTimeField(auto_now_add=True)
Смежные вопросы
Несколько ресурсов нашли подходящее решение здесь Как отфильтровать / уменьшить QuerySet для каждой n-й строки? и { ссылка }, основанный на аннотировании с помощью буквы «F», например:
views.py
Measurement.objects.annotate(idmod2=F('id') % 2).filter(idmod2=0)
Это работает до некоторой степени, однако измерения производятся с помощью ~ 5- 25 различных датчиков и приходят каждые ~ 1-15 минут, поле id не отслеживается постоянно. Просто для наглядности упрощенный пример:
+----+--------+------+-------+
| id | sensor | data | time |
+----+--------+------+-------+
| 1 | A | 432 | 10:00 |
| 2 | A | 534 | 10:15 |
| 3 | B | 2342 | 10:20 |
| 4 | B | 87 | 10:25 |
| 5 | B | 2 | 10:30 |
| 6 | B | 982 | 10:45 |
| 7 | A | 23 | 10:45 |
| 8 | B | 400 | 10:50 |
+----+--------+------+-------+
Если теперь кто-то пытается отфильтровать для датчика 'A' с% 2, список выглядит только как
| 2 | A | 534 | 10:15 |
, а для 'B'
| 4 | B | 87 | 10:25 |
| 6 | B | 982 | 10:45 |
| 8 | B | 400 | 10:50 |
Оконная функция
Я думал об использовании Window функции Django
Measurement.objects.annotate(place=Window(expression=RowNumber(),partition_by=[F('sensor')], order_by=F('time').desc()))
, которая дает
django.db.utils.NotSupportedError: Window is disallowed in the filter clause.
И это также упоминается в документах
По умолчанию False. Стандарт SQL запрещает ссылаться на оконные функции в предложении WHERE, а Django вызывает исключение при создании QuerySet, который будет делать это
и вытекает из логической обработки SQL , который сначала проходит через WHERE перед SELECT, поэтому нет способа выполнить этот запрос.
Вопрос
Что такое достаточно быстрый способ выборка этого временного ряда, чтобы уменьшить набор данных? В идеале я бы пропустил фильтр по времени и датчику
.filter(sensor=thisSensor).filter(time__range=(rangeStart, rangeEnd))
и показал бы подвыборку, скажем, 200 записей.