我在Drools中苦苦挣扎,有人能澄清我是否以错误的方式看待这个问题吗?该解决方案有效,但似乎是错误的方法,正如我将在最后解释的那样。
我有一个包含ID,洲,区域的Country模型对象;区域是经济区域,例如欧盟或美国; 我有CountryID,EconomicAreaId,ContinentID的枚举; 我有一个Request对象,包含origin:Country,destination:Country,srucharge:Int; 我有两个Drools规则(实际上以xls表示,但我将在此处列出drl):
<package and imports are correct>
rule "UK"
when
$c:Country($c.getId() in (CountryID.UNITED_KINGDOM))
then
$c.setArea(EconomicAreaID.EU);
$c.setContinent(ContinentID.EUROPE);
/* update($c); // I tried this too :) //
end
rule "US"
when
$c:Country($c.getId() in (CountryID.UNITED_STATES))
then
$c.setArea(EconomicAreaID.US);
$c.setContinent(ContinentID.N_AMERICA);
end
rule "EU to EU"
when
$rr:ChargeRequest($rr.getOrigin.getArea() == EconomicAreaID.EU, $rr.getDestination.getArea() == EconomicAreaID.EU)
then
$rr.setCharge(1);
end
rule "US to US"
when
$rr:ChargeRequest($rr.getOrigin.getArea() == EconomicAreaID.US, $rr.getDestination.getArea() == EconomicAreaID.US)
then
$rr.setCharge(2);
end
rule "EU to US"
when
$rr:ChargeRequest($rr.getOrigin.getArea() == EconomicAreaID.EU, $rr.getDestination.getArea() == EconomicAreaID.US)
then
$rr.setCharge(3);
end
rule "US to EU"
when
$rr:ChargeRequest($rr.getOrigin.getArea() == EconomicAreaID.US, $rr.getDestination.getArea() == EconomicAreaID.EU)
then
$rr.setCharge(4);
end
首先,我想插入两个国家对象,即起源和目的地,并让Drools自动将大陆和经济区分配给它们的属性;
然后我要Drools计算附加费,这里简化为整数。
为此,我必须同时添加国家对象并触发所有规则以填充国家对象,然后添加请求对象并再次触发所有规则以获取附加费用。
KieSession kSession = kieContainer.newKieSession();
ChargeRequest rr = new ChargeRequest(new Country("UNITED_STATES"), new Country("UNITED_KINGDOM"));
kSession.insert(rr.getOrigin()); // add both country objects
kSession.insert(rr.getDestination());
kSession.fireAllRules(); // LINE 6 : fire rules to calculate the economic areas and continents of the country objects
kSession.insert(rr); // add the ChargeRequest object
kSession.fireAllRules(); // fire the rules to calculate the charge
return rr.toString(); // ChargeRequest(origin=Country(id=UNITED_STATES, continent=N_AMERICA, area=US), destination=Country(id=UNITED_KINGDOM, continent=EUROPE, area=EU), charge=4)
如果我省略第6行,则费用不会计算为4,因为Drools对人口不足的国家对象执行费用规定。我以为Drools具有按正确顺序评估所有规则的概念,因此在将规则用作收费规则的输入之前,它会“知道”将规则应用于各个国家/地区。
这只是我正在使用的简化示例,因此似乎不应该这么复杂,所以我弄错了概念方法吗?
答案 0 :(得分:2)
哦,Drools知道如何以及何时评估您的规则,请确保确实如此。唯一的是,当模型中的某些内容发生变化时,您必须让它知道。 您在规则右侧调用的设置器永远不会通知Drools,因此它不知道您所做的更改。
Drools中有一个名为modify
的特殊关键字,可以在模型中发生更改时通知引擎。
设置区域和大陆的规则应如下所示(具体取决于您正在执行的Drools版本,使用modify
时可能会遇到无限循环。我已经改写了左侧您可以避免的规则):
rule "UK"
when
$c:Country(
area == null,
continent == null,
id in (CountryID.UNITED_KINGDOM)
)
then
modify($c){
setArea(EconomicAreaID.EU),
setContinent(ContinentID.EUROPE)
};
end
现在,第二个问题是,在设置费用的规则中,Country
嵌套在ChargeRequest
对象中。 Drools不会自动理解,当您修改Country
时,它必须重新评估与ChargeRequests
相关的规则。您必须明确指出这一点:
rule "EU to EU"
when
$rr:ChargeRequest(
$origin: origin,
$destination: destination
)
Country(
this == $origin,
area == EconomicAreaID.EU
)
Country(
this == $destination,
area == EconomicAreaID.EU
)
then
$rr.setCharge(1);
end
如您所见,Drools很聪明,但是您需要稍微帮助他;)
根据一组固定的条件处理此类参数化值时,更好的方法是将条件本身建模为事实:
1.-创建一个类来对约束和结果进行建模:
public class RequestCharge{
private EconomicAreaID origin;
private EconomicAreaID destination;
private double charge;
//getters and setters
}
2.-将所有约束插入会话:
kSession.insert(new RequestCharge(EconomicAreaID.EU, EconomicAreaID.EU, 1.0);
kSession.insert(new RequestCharge(EconomicAreaID.US, EconomicAreaID.US, 2.0);
kSession.insert(new RequestCharge(EconomicAreaID.EU, EconomicAreaID.US, 3.0);
kSession.insert(new RequestCharge(EconomicAreaID.US, EconomicAreaID.EU, 4.0);
3.-有一条规则来处理所有请求(您可能想添加一条额外的规则来处理与任何已配置的RequestCharges
不匹配的请求):
rule "Apply Charge"
when
$rr:ChargeRequest(
$origin: origin,
$destination: destination
)
$o: Country( //You still need these Country patterns to react to the changes in the first rule
this == $origin
)
$d: Country(
this == $destination
)
RequestCharge(
origin == $o,
destination == $d,
$charge: charge
)
then
$rr.setCharge($charge);
end
希望有帮助,