锁定老帖子 主题:技巧:使用规则寻找最大值
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
||||
---|---|---|---|---|
作者 | 正文 | |||
发表时间:2007-07-13
有时你可能想查找fact的最大值。你可以通过使用not实现这个目的,如下例所示(如果你喜欢也可以将它放在一个Query中):<o:p></o:p> <o:p> </o:p> rule "Highest Temperature for a Day"<o:p></o:p> when<o:p></o:p> Day(highest : temp)<o:p></o:p> not Day(temp > highest)<o:p></o:p> then...<o:p></o:p> <o:p> </o:p> 感谢Mitch Christensen 提供建议. <o:p></o:p> [译者注:<o:p></o:p> 这里为一些初学者解释一下上面规则的执行思路,在说明之前我们先回顾Drools中对于Fact匹配有一个原则:在没有限制条件的情况下,引擎寻找最大限度的组合<o:p></o:p> 回到规则分析,假设在Working Memory中设置了三个Day对象,temp分别是10,20,30;那么考虑一下规则引擎如何执行。<o:p></o:p> 首先规则的第一个条件是Day(highest : temp)没有对Day有过滤限制,则上面三个Day对象都会尝试激发"Highest…"规则。假设Day(10)先进入,则对第二个条件,因为highest是上一个条件传过来的变量,所以引擎会为highest和temp建立3种组合:[ Day(10) , Day(10) ] [ Day(10) , Day(20) ] [ Day(10) , Day(30) ],显然后两种组合对于not Day(temp > highest)是不成立的。由此类推只有当Day(30)尝试激发规则时才能满足两个条件。<o:p></o:p> ]<o:p></o:p> Fact的排序过程<o:p></o:p> 类似的方法通常用来对一组关联的fact进行排序处理。例如,要按照timestamp(时间戳)的顺序处理一组Alert Fact,你可以如下进行:<o:p></o:p> rule "Process Alerts by time received"<o:p></o:p> when<o:p></o:p> $alert : Alert($oldest : timestamp)<o:p></o:p> not Alert(timestamp < $oldest)<o:p></o:p> then<o:p></o:p> // process the Alert in some application specific way<o:p></o:p> $alert.process()<o:p></o:p> <o:p> </o:p> // 必须将处理过的Alert从Working Memory中删除<o:p></o:p> // 否则引擎不会对Working Memory中的Fact重新评估<o:p></o:p> retract($alert);<o:p></o:p> end<o:p></o:p> 该规则将按照Alert中的timestamp属性的早晚来依次进行处理,完成处理的Alert从working memory中删除,接着进行下一个的处理。<o:p></o:p> -Mitch Christensen <o:p></o:p> Mitch 提供的这种模式是最简单的但不是最有效率的。简单来说,如果有1000个Day对象在Working Memory中,则引擎要对 (1+2+…+1000)种组合进行判断(考虑到Drools引擎在碰到第一个不满足条件的组合时就会抛弃Fact)。显然在Day对象数量过于庞大时,这种判断方法会成为性能瓶颈。因此下面是改进后的判断最大值规则:<o:p></o:p> <o:p> </o:p> rule "Try day"<o:p></o:p> when<o:p></o:p> $d : Day($temp : temp)<o:p></o:p> then<o:p></o:p> assert(new TryDay($d));<o:p></o:p> end<o:p></o:p> <o:p> </o:p> rule "Highest unknown"<o:p></o:p> when<o:p></o:p> $attempt : TryDay($d : day)<o:p></o:p> not (Highest())<o:p></o:p> then<o:p></o:p> assert (new Highest($d));<o:p></o:p> end<o:p></o:p> <o:p> </o:p> rule "Highest lower"<o:p></o:p> when<o:p></o:p> $highest: Highest($highDay : day)<o:p></o:p> $attempt : TryDay($day : day -> ($day.getTemp() > $highDay.getTemp()))<o:p></o:p> then<o:p></o:p> $highest.setDay($day);<o:p></o:p> modify($highest);<o:p></o:p> end<o:p></o:p> <o:p> </o:p> rule "Highest higher"<o:p></o:p> when<o:p></o:p> Highest($highest: day)<o:p></o:p> $attempt : TryDay($day : day -> ($day.getTemp() <= $highest.getTemp()))<o:p></o:p> then<o:p></o:p> retract($attempt);<o:p></o:p> end<o:p></o:p> rule "Print highest"<o:p></o:p> salience -10<o:p></o:p> when<o:p></o:p> Highest($day : day)<o:p></o:p> then<o:p></o:p> System.out.println("Highest day is " + $day);<o:p></o:p> end<o:p></o:p> Steven Williams <o:p></o:p> 经过测试,当Day的数量为1000时,Mitch的规则执行时间约2000毫秒,而Steven的规则为223毫秒;当Day的数量为2000时,Mitch的规则执行时间约8000毫秒,而Steven的规则为345毫秒<o:p></o:p> 更多关于查找最大值<o:p></o:p> “查找最大值”的问题通常并不限制于对单个属性或字段进行比较。<o:p></o:p> <o:p> </o:p> 当面对这个问题时,让我们概括它为“发现最好”或“发现最佳”的模式,这在现实中是非常有可能碰到的。如最好的投资机会,最好的网络节点,最好的保险策略等等。 假设我们的任务不是仅仅发现最高的温度,而是有一个组合的温度——最高的温度与最高的dewPoint。 public class HeatRecord<o:p></o:p> {<o:p></o:p> int temp;<o:p></o:p> int dewPoint;<o:p></o:p> .<o:p></o:p> .<o:p></o:p> }<o:p></o:p> 一个简单的解决方案可能是: <o:p></o:p> rule "Filter" // 测试每一个,如果被另一个超越则删除<o:p></o:p> salience 100<o:p></o:p> when<o:p></o:p> HR1 : HeatRecord($t1:temp, $d1:dewPoint )<o:p></o:p> HeatRecord( temp > $t1 ) || HeatRecord( temp == $t1, dewPoint > $d1 )<o:p></o:p> then <o:p></o:p> retract( HR1 );<o:p></o:p> end<o:p></o:p> <o:p> </o:p> rule "Report" // 报告留下了什么<o:p></o:p> salience 50<o:p></o:p> when<o:p></o:p> HR1 : HeatRecord( )<o:p></o:p> then<o:p></o:p> System.out.println("The Most Sweltering Conditions were: " + HR1.getTemp() +" "+ HR1.getDewPoint() ); <o:p></o:p> end<o:p></o:p> <o:p> </o:p> 如果我们试图使用Steven Williams 提到的方法,它将会是多大?怎样维护? <o:p></o:p> 想一想? <o:p> </o:p> 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
||||
返回顶楼 | ||||
浏览 2436 次