【问题标题】:How to check index numbers from database using Django?如何使用 Django 从数据库中检查索引号?
【发布时间】:2021-07-15 17:09:00
【问题描述】:

我有一个内置在 Django 中的系统来接收数据。我存储数据如下:

 id | sensor | message_id | value
----+--------+------------+-------
 1  | A      | 1          | xxx    
 2  | A      | 2          | xxx
 3  | A      | 3          | xxx
 4  | B      | 1          | xxx
 5  | B      | 2          | xxx
 6  | B      | 4          | xxx
 7  | B      | 7          | xxx

我们预计message_id 会随着每条后续消息而增加每个传感器。如您所见,传感器 B 的 message_id 为:1、2、4、7。这意味着传感器 B 缺少编号为 3、5 和 6 的消息。在这种情况下,我们需要调查丢失的消息,尤其是如果有很多失踪。所以我现在想要一种方法来了解这些丢失的消息何时发生。

所以我想检查过去五分钟内是否丢失了一条消息。我希望输出类似于:

在过去 5 分钟内传感器 B 缺少 3 条消息。缺少以下 id:3、5、6

我想到的最简单的方法是查询一个传感器的 message_id,然后遍历它们以检查是否跳过了任何数字。我想到了这样的事情:

five_minutes_ago = datetime.now() - timedelta(minutes=5)
queryset = MessageData.objects.filter(created__gt=five_minutes_ago).filter(sensor='B').order_by('message_id')
last_message_id = None
for md in queryset:
    if last_message_id is None:
        last_message_id = md.message_id
    else:
        if md.message_id != last_message_id + 1:
            missing_messages = md.message_id - last_message_id - 1
            print(f"{missing_messages} messages missing for sensor {md.sensor}")

但由于我有数百个传感器,这似乎不是最好的方法。甚至可以在 SQL 本身中执行此操作,但我不知道有什么方法可以这样做。

谁能告诉我如何有效地做到这一点?

【问题讨论】:

  • 出现这种情况是什么意思?
  • @Strawberry - 这意味着在此过程中某处丢失了一条消息。
  • 想要的结果应该是什么样子?请相应地编辑您的问题。
  • 另外,如果它是丢失的第一条消息怎么办?还是最后一个!?!
  • @Strawberry - 我编辑了问题以解释传感器 B 缺少 3 号。如果 5 分钟内的第一条消息丢失,那就太可惜了。我可能会每 5 分钟检查最后 10 分钟以解决此问题。现在的主要问题是如何更有效地检查所有传感器。

标签: python sql django postgresql


【解决方案1】:

您可以使用一条 SQL 语句完成您想要的。以下为丢失消息 ID 的数组和每个传感器的丢失消息数生成。这分 3 步完成:

  1. 获取最小和最大消息 ID。
  2. 生成所需消息 ID 的密集列表。
  3. 将实际传感器消息与密集列表左连接并选择 只有密集列表中的那些不在实际表中。数数 选择的项目。
with sensor_range (sensor, min_msg_id, max_msg_id) as           -- 1 get necessary message range 
     ( select sensor
            , min(message_id)
            , max(message_id) 
         from sensor_messages 
        group by sensor
       -- where message_ts > current_timestamp - interval '5 min) 
     )  --select * from sensor_range;
     , sensor_series (sensor, msg_id) as                        -- 2 generate list of needed messages_id 
       ( select sensor, n 
           from sensor_range  sr 
           cross join generate_series( sr.min_msg_id
                                     , sr.max_msg_id
                                     , 1
                                     ) gs(n)
        ) --select * from sensor_series;
select ss.sensor
     , array_agg(ss.msg_id)  missing_message_ids                 --3 Identify messing message_id and count their number 
     , array_length(array_agg(ss.msg_id),1) missing_messages_count
  from sensor_series        ss
  left join sensor_messages sm 
         on (    ss.sensor = sm.sensor 
             and sm.message_id = ss.msg_id
            )
where sm.message_id is null 
group by ss.sensor 
order by ss.sensor; 

demo here。如果需要,可以将其打包到返回表的 SQL 函数中。好reference

您的描述中提到了时间范围,但您的数据没有时间戳列。该查询包含处理此问题的注释。

【讨论】:

    【解决方案2】:

    你可以试试这样的,我已经在上面添加了 cmets 用于逻辑,如果有任何疑问,请随时发表评论。

    five_minutes_ago = datetime.now() - timedelta(minutes=5)
    queryset = MessageData.objects.filter(created__gt=five_minutes_ago).filter(sensor='B').order_by('message_id')
    
    # rows that should ideally be there if no message_id was missing, i.e. equal to last message_id
    ideal_num_of_rows = queryset.last().message_id
    
    # total number of message_id present
    total_num_of_row_present = queryset.count()
    
    # number of missing message_ids 
    num_of_missing_message_ids = ideal_num_of_rows - total_num_of_rows_present - 1 
    

    【讨论】:

    • 请注意,.filter(created__gt=five_minutes_ago) 可能会过滤掉MessageData 的一些实例,因为在这种情况下传感器会给出错误的计数。
    • @AbdulAzizBarkat 有效点,我只是在问题中使用了查询集。我回答的主要原因是简化缺少 message_ids 的逻辑
    • 这是一个很好的观点。但它实际上并没有测试数据的顺序。在某些情况下,数据可以稍后到达。但它应该总是按顺序到达。因此,如果最后 5 条消息丢失,那仍然可以,因为没有违反 message_id 的顺序。不过还是感谢您的建议,我可能也会使用此检查。
    • @kramer65 你能用一个测试用例和预期的输出来解释吗?也感谢您的支持。
    • 我编辑了问题以更好地解释我期待什么样的消息。
    猜你喜欢
    • 1970-01-01
    • 2020-06-09
    • 2017-12-04
    • 2021-06-27
    • 2021-12-31
    • 2019-05-30
    • 2020-08-03
    • 1970-01-01
    • 2020-03-05
    相关资源
    最近更新 更多