【问题标题】:Storing Action Rules存储动作规则
【发布时间】:2020-07-22 16:45:24
【问题描述】:

我有一个应用程序可以接收来自物联网设备的数据,例如温度、水位等信息。

我需要实现一种方法来存储设备的规则,例如用户可以指定“如果温度 > 30,则发送消息/执行操作”。所以参数 A >/== Value 然后做 X。

如何将规则存储在数据库中,以便每隔 X 分钟就这些规则运行作业?运行 Jobs 很简单,我可以做技术方面的工作,但我只是被存储逻辑难住了。

如果我们可以递归/嵌套语句,那就太好了,但我只是在寻找一些简单的指导。

非常感谢您的帮助。

【问题讨论】:

  • 设备可以拥有的规则的完整格式示例会很有帮助。另外,数据库中的设备是如何处理的?换句话说,是否存在按设备保存信息的表?这样做的架构大纲也会有所帮助。
  • 嗨,感谢您的回复,数据存储在 dataLogTable 中,存储设备序列号、参数 1(温度)、参数 2(级别)、参数 3(日/夜),因为它们来自设备发送的 Json 消息。设备发送的参数有 20 个,其中大部分是从 Json 转换为 Double(temp, Level, Humidity)、Bool(open/close,day/night)、Timestamp 等字段。设备是自己的对象,(设备ID、序列号、名称)。当消息进入时,一台设备可以有多个 DataLog 条目。设备规则将在 DataLog 表上运行,我希望这可以澄清。
  • 应用程序会在作业中运行规则吗?如果是这样,我将创建一个 rules 表,其中包含 rule_id(PK) 、device_id rule_fld (作为 varchar)。一个设备可能有很多规则。然后在间隔获取 device_id 的规则并处理它们。

标签: c# postgresql rule-engine .net-core-3.1


【解决方案1】:

我会用一个规则表、一个条件表和一个 动作表,后 2 个具有 FK 到第 1 个。条件 表也​​将有一列指示要测试的字段, 表示操作符的列,以及表示值的列 将其与 ('>' 和 30 在您的示例中) 进行比较。动作表只有一个 用于指示操作的列,可能还有一个额外的列 详细信息(可能分别是“发送电子邮件”和“foo@example.com”); 这将是 jsonb 列的一个不错的候选人,因为这些操作 可能需要做各种各样的附加数据 他们的工作。

您的工作只需将条件表与最近的数据连接起来 点,可能使用 WHERE 时间戳 > 作业上次运行的时间。

SELECT actions.* FROM
data_table t
JOIN rules on rules.device_id=t.device_id
JOIN conditions on conditions.rule_id=rules.id
JOIN actions on actions.rule_id=rules.id
WHERE (
 (conditions.field='temperature' and conditions.operator='>' and data_table.temperature > conditions.value)
 OR (conditions.field='temperature' and conditions.operator='<' and data_table.temperature < conditions.value)
 OR (conditions.field='water level' and conditions.operator='>' and data_table.water_level > conditions.value)
 OR (conditions.field='water level' and conditions.operator='<' and data_table.water_level < conditions.value))
  AND data_table.your_timestamp_column > '2020-07-22 10:01:02' -- the last time your job ran.

您可以将作业上次运行的时间戳存储在任何持久性中 贮存。有一张只有 job_name 和 您的作业在启动时查询以获取的 last_completion_time 列 用于时间戳比较的值,然后更新 完成时处理的 data_table 时间戳的最大值。

将字段 & 运算符映射到 SQL 表达式的 WHERE 子句将 相当大,但这种事情会很冗长 或其他。也许您可以改为使用 CASE 语句来提取 字段值,以便您拥有的子句数量与 字段数 + 运算符数而不是字段数 * 运算符的数量,例如:

SELECT
actions.* FROM (
  SELECT actions, t, conditions,
  CASE WHEN conditions.field='temperature' THEN t.temperature
       WHEN conditions.field='water level' THEN t.water_level
  END AS data_value
  data_table t
  JOIN rules on rules.device_id=t.device_id
  JOIN conditions on conditions.rule_id=rules.id
  JOIN actions on actions.rule_id=rules.id
  WHERE data_table.your_timestamp_column > '2020-07-22 10:01:02'
) AS inner_1
WHERE (
  (conditions.operator = '>' AND data_value > conditions.value)
  OR (conditions.operator = '<' AND data_value > conditions.value)
)

但是如果 data_value 的可能字段,这将遇到问题 没有相同的类型。你可以通过一个来解决这个问题 column-per-type,然后为每种类型定义一组可用的运算符:

-- ...
  CASE WHEN conditions.field='temperature' THEN t.temperature
       WHEN conditions.field='water level' THEN t.water_level
  END AS data_value_numeric,
  CASE WHEN conditions.field='device is enabled' THEN t.device_is_enabled
  END AS data_value_bool
-- ...
WHERE
(
  (conditions.operator = '>' AND data_value_numeric > conditions.numeric_value)
  OR (conditions.operator = '<' AND data_value_numeric > conditions.numeric_value)
  OR (conditions.operator = '=' AND data_value_bool > conditions.bool_value)
)

但在这一点上,我们离杂草还很远。希望这可以 开始吧。

【讨论】:

  • 您好,对于延迟回复,我深表歉意,我仍在尝试解决此问题,并使用您的建议。这是一个逻辑问题,而不是技术问题。我想我可能有一个解决方案,一旦我开始工作就会发布。再次感谢
猜你喜欢
  • 2017-01-25
  • 2017-08-11
  • 2018-07-02
  • 2017-08-02
  • 1970-01-01
  • 2021-01-03
  • 2020-11-28
  • 2017-06-16
相关资源
最近更新 更多