【发布时间】:2020-05-19 09:21:32
【问题描述】:
目标
我正在尝试通过对时间序列进行二次采样来减少发送到应用程序前端的数据。最初只取第 n 行,因为我还想优化速度。
布局
我正在使用带有 PostgreSQL 后端的 Django 2.1.5。 时间序列表每 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)
相关问题
这里有一些资源围绕一个封闭的解决方案 How to filter/reduce a QuerySet to every nth row? 和 https://stackoverflow.com/a/56487889/11225898 这是基于像这样用'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 |
+----+--------+------+-------+
如果现在尝试使用 %2 过滤传感器“A”,则列表看起来像
| 2 | A | 534 | 10:15 |
对于“B”
| 4 | B | 87 | 10:25 |
| 6 | B | 982 | 10:45 |
| 8 | B | 400 | 10:50 |
窗口函数
我想到了使用Django的Window函数
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.
这在docs中也提到了
默认为假。 SQL 标准不允许引用窗口 WHERE 子句中的函数和 Django 在以下情况下引发异常 构造一个可以做到这一点的查询集
并且源于SQL logical query processing,在SELECT之前先经过WHERE,所以没有办法执行这个查询。
问题
对这个时间序列进行二次抽样以减少数据集的合理快速方法是什么?理想情况下,我会通过时间和传感器的过滤器
.filter(sensor=thisSensor).filter(time__range=(rangeStart, rangeEnd))
并显示一个子样本,比如 200 条记录。
【问题讨论】: