考虑以下变量由播放器分析器服务生成:
level = 6;
errors = 4;
score = 12;
...
我们有一些规则和信息:
1. errors == 0 AND level > 5 : Senior player
2. score == 10 OR errors == 3: Border line player
3. score > 10 AND score < 13: Not good, just passed
4. ...
另一个例子:考虑以下变量由 food 分析器服务生成:
fruit = 2;
coca = 6;
...
我们有一些规则和信息:
1. fruit == 0 : Consider buying some fruits
2. coca == 0: That's healthy
3. ...
我应该如何在像MySQL这样的RDBMS中保存规则和消息,以便查询和查找消息变得容易。
最糟糕的方法是将规则保存在一列中,将消息保存在另一列中,然后加载每个记录以使用主机编程语言进行测试。
你能为这种情况建议一个更好的方法吗?当我们有几千条消息时,这不是一个好方法,我们需要一种方法来过滤数据库端的消息。
答案 0 :(得分:0)
所有这些列和表的含义是什么?
<强> PROPERTY_NAME 强>
这包含可以对其进行检查的所有内容的列表。
<强>运算符强>
包含用于每个属性的不同运算符的列表。
<强> rule_message 强>
存储正在显示的实际消息。
<强> operator_property 强>
这是所有其他三个表之间的连接表,包含您的规则和逻辑。
如何使用此设计: *您可以将所有属性和运算符添加到表中。 *要查找要为场景显示的消息,例如检查播放器的显示内容:
SELECT rn.rule_message_id, rm.message
FROM rule_message rm
INNER JOIN operator_property op ON rm.rule_message_id = op.rule_message_id
INNER JOIN property_Name pn ON op.property_id = pn.property_id
INNER JOIN operator o ON op.operator_id = o.operator_id
WHERE 1=1
AND (
pn.property_name = "errors"
AND pn.operator_symbol = "=="
AND op.check_value = 0
)
AND (
pn.property_name = "level"
AND pn.operator_symbol = "5"
AND op.check_value = 5
)
理想情况下,此查询将返回1行。如果返回0,则不应用任何消息。如果它返回2或更多,则表示它不能完全符合您的一个标准,因此没有任何消息适用。
希望这有帮助!我以前written articles on desigining databases,我能给你的最好的建议就是弄清楚数据的用途,看起来你已经拥有了。
另外,如果你能想到更好的桌子名称,那就去吧 - 这只是一个快速的设计来说明这一点。
答案 1 :(得分:0)
一般来说,这种规则解释不是直接在数据库中完成的,最终会在像check_rules_against_data
这样的解释器中完成,这绝对没问题。
直接在一个或多个php文件中编写所有规则是很常见的(当然由一些代码包围if ($rule) { echo $message; }
)。它通常比每次动态评估每个规则更快(并且请记住,数据库也必须这样做)。如何编码过滤器取决于您的需求;您可以坚持您的规则格式,您可以只显示完整的PHP代码并让用户编辑它,您可以将它们拆分并使用数据库设计来实现,例如验证变量是否存在(参见下面的扩展rule_term
- 表或completeitpro的答案)。所有这些都可以正常工作。
如果您愿意,或者您想测试它,您可以在数据库中进行一些预选。有很多方法可以做到这一点,并且有很多方法可以针对特殊情况进行优化,这将大大取决于你真正想做的事情,所以我只想描述一种方式,给你一个想法。
你的变量看起来你会有很多,但所有这些变量都是整数(因此拥有一个焦炭并不意味着:Items[x]='COCA'
,但coca=1
),所以你可以放他们和表格中的规则如下:
可变
variableid | variablename | variabletype
----------------------------------------
1 | errors | 1
2 | level | 1
3 | score | 1
user_variable
userid | variableid | valueint
-------------------------------------
1 | 1 | 0
1 | 2 | 6
1 | 3 | 10
2 | 1 | 3
2 | 3 | 10
3 | 1 | 0
3 | 2 | 6
3 | 3 | 10
4 | 1 | 0
4 | 2 | 5
规则
ruleid | mincount | message
---------------------------
1 | 2 | Senior player -> AND (2 terms have to fit)
2 | 1 | Border line player -> OR (any 1 term can fit)
rule_term
ruleid | variableid | minvalueint | maxvalueint
-----------------------------------------------
1 | 1 | 0 | 0 -> error == 0
1 | 2 | 6 | 9999 -> level > 5
2 | 1 | 3 | 3 -> error == 3
2 | 3 | 10 | 10 -> score == 10
根据这些规则,您现在可以预先选择点击的规则:
select user_variable.userid, rule.ruleid, count(*) as cntfulfilled,
max(rule.mincount) as mincnt, max(rule.message) as message
from rule_term
join rule
on rule_term.ruleid = rule.ruleid
join user_variable
on rule_term.variableid = user_variable.variableid
and rule_term.minvalueint <= user_variable.valueint
and rule_term.maxvalueint >= user_variable.valueint
group by user_variable.userid, rule.ruleid
having count(*) >= max(rule.mincount);
这应该计入每个用户和每个规则,满足此规则的子节点数。如果我没有弄错的话,这应该是:
userid | ruleid | cntfulfilled | mincnt | message
--------------------------------------------------
1 | 1 | 2 | 2 | Senior player
1 | 2 | 1 | 1 | Border line player
2 | 2 | 2 | 1 | Border line player
3 | 1 | 2 | 2 | Senior player
要表达AND
,mincnt
应该是所有子条目的数量,对于OR
,它将是1.使用普通AND
或{{构建规则1}},这已经是完整的测试。
对于更复杂的规则,您必须能够在php中重新创建规则以将其放入检查功能中。你可以,例如将其编码在如下表格中:
扩展OR
- 表格:
rule_term
我使用cond = 1 :(,cond = 2 :),cond = 3:NOT,cond = 4:AND,cond = 5:OR。 (有更好的方法对它进行编码,例如只表达逻辑并将其分组到嵌套的ruleid | pos | cond | var.id | min | max
--------------------------------------------
3 | 1 | 1 | 0 | 0 | 0 -> (
3 | 2 | 0 | 1 | 1 | 1 -> error == 1
3 | 3 | 4 | 2 | 5 | 5 -> AND level == 5
3 | 4 | 2 | 0 | 0 | 0 -> )
3 | 5 | 5 | 3 | 10 | 10 -> OR score == 10
- 子组中,但这里不会改进任何东西)。
这将允许您仍然预先选择可能适合的规则,以获得您之后必须在php中分析的规则(您不能再使用mincnt,因为即使只是AND
,mincnt也将为1,而不仅仅是error == 1
)。
您可以添加更多内容:您可以添加字符串变量类型(向score == 10
和valuestr
添加列user_variable
并调整联接)或标记为&#39 ; NOT&#39;,如果您能够在rule_term-table中的行中表达它们,则可以向连接添加更复杂的copndition(例如,组合2个变量并在双连接中检查2个变量)。
它有点困难,但您可能希望使用左连接和一些额外的逻辑来比较不存在的变量(例如,如果您不想设置变量rule_term
适合所有人,只适用于有(或有)可乐的用户。
如果你想使用水平变量(一列中固定数量的变量),你应该对规则项(每个变量的最小/最大列)做同样的事情,并调整连接以检查每个变量列。
这只是一个普遍的想法,您显然有很多替代方法可以做到这一点,最佳选择和优化将在很大程度上取决于您的实际需求,并花更多时间考虑您的数据库设计(或如何生成动态php文件)稍后会减少挫折(很多)或提高速度(很多)。我会再次提醒你,测试生成动态php文件的选项 - 这通常要快得多。
答案 2 :(得分:0)
这是规则系统的经典案例,可能不会在数据库中实现。我把一个java库(Rulette)组合在一起,它可以做到这一点。
基本上,您可以通过创建rule_system表并向其中插入条目来设置它,并创建包含条目的规则输入表(级别,错误,分数)。根据您的样本,级别和错误似乎是“值”&#39;类型的同时得分&#39;似乎是一个&#39; RANGE&#39;类型。
现在,您可以创建规则表(&#39; player_rules {id,level,error,score}&#39;)来配置您的所有规则,并将它们映射到输出表格中的条目(&#39; player_message { id,message}&#39;)。
很高兴!!
RuleSystem rs = new RuleSystem("player-rule-system");
Rule r = rs.getRule(new HasMap<>(){"level":level, "error: : error, "score" : score});