【发布时间】:2018-08-28 15:22:26
【问题描述】:
我正在构建一个规则引擎,其中一些规则是低级“if-then”规则之上的逻辑谓词。
换句话说,我有一个连接表,用于存储用户之间的匹配项以及这些用户满足的规则。一旦处理了低阶规则,引擎就会评估高阶规则并为满足它们的用户创建新匹配。
'user_matches':
+---------+---------+-----------+
| rule_id | user_id | rule_type |
+---------+---------+-----------+
| 1 | 1 | simple |
+---------+---------+-----------+
| 2 | 1 | simple |
+---------+---------+-----------+
| 1 | 2 | simple |
+---------+---------+-----------+
| 3 | 1 | compound |
+---------+---------+-----------+
在上面的示例中,规则#3 要求用户同时满足规则#1 和规则#2。用户 #1 匹配此规则,用户 #2 不匹配。
由于我想避免多次访问数据库,我需要一种方法将此类谓词转换为普通 SQL 查询,然后将其传递给 Arel::InsertManager。这是它的要点:
UserMatch.select(UserMatch.arel_table[:user_id])
.where(UserMatch.arel_table[:rule_id].eq(1)
.and(UserMatch.arel_table[:rule_id].eq(2))).to_sql
=> SELECT "user_matches"."user_id"
FROM "user_matches"
WHERE ("user_matches"."rule_id" = 1
AND "user_matches"."rule_id" = 2)
我将规则树存储为 JSON:
{
"or":[
{
"and":[
{
"or":[
21,
42
]
},
84
]
},
{
"or":[
168,
336
]
}
]
}
如您所见,问题在于这些规则可以以无数种方式嵌套。所以我可能在这里需要一个递归循环。一个都想不出来希望你们能帮助我,至少给我一个指导,告诉我如何将这个 JSON 伪 AST 树解析为实际的 Arel AST 树。
谢谢!
更新:事实证明你不能在 SQL 语句中使用同一个表两次,请参阅下面的答案。
【问题讨论】:
-
另外,我想要一个干净的解决方案,不连接 SQL 字符串或
evaling 字符串,其中包含 ruby 代码。 -
构建了规则引擎后,我的想法是您的问题可能过于广泛,无法在此处进行有意义的解决。但是,祝你好运 - 这是一个大项目!
-
@jvillian 我要求一种算法将类似 AST 的 JSON 树解析为 ActiveRecord 用于在 Rails 中构建 SQL 查询的实际 Arel AST 对象。猜你不明白这个问题,这与规则引擎本身无关。
-
是的,我明白这个问题。而且,范围很广。 “如何将这个 JSON 伪 AST 树解析成 ActiveRecord 理解的实际 Arel AST 树” 可不是小事。最后,我发现构建引擎非常有益。希望你一切顺利。
标签: ruby-on-rails ruby rails-activerecord arel