在属性和包含对象上执行 Drools 规则的顺序
Ordering of executing Drools rules on attributes and containing object
我对 Drools 中的一个概念有点困惑,谁能澄清我是否以错误的方式看待这个问题?该解决方案有效,但似乎是错误的方法,我将在最后解释。
我有一个 Country 模型对象,包含 id、continent、area;其中 area 是经济区,例如欧盟或美国;
我有 CountryID、EconomicAreaId、ContinentID 的枚举;
我有一个包含 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计算附加费,这里简化为一个int。
为此,我必须添加两个国家/地区对象并触发所有规则以填充国家/地区对象,然后添加请求对象并再次触发所有规则以获取附加费。
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 具有以正确顺序评估所有规则的概念,因此它将 "know" 将规则应用于国家/地区,然后再将它们用作收费规则的输入。
这只是我正在玩的一个简化示例,所以它似乎不应该这么复杂,所以我的概念方法有误吗?
哦,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.- 创建一个 class 来模拟约束和结果:
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
希望对您有所帮助,
我对 Drools 中的一个概念有点困惑,谁能澄清我是否以错误的方式看待这个问题?该解决方案有效,但似乎是错误的方法,我将在最后解释。
我有一个 Country 模型对象,包含 id、continent、area;其中 area 是经济区,例如欧盟或美国; 我有 CountryID、EconomicAreaId、ContinentID 的枚举; 我有一个包含 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计算附加费,这里简化为一个int。
为此,我必须添加两个国家/地区对象并触发所有规则以填充国家/地区对象,然后添加请求对象并再次触发所有规则以获取附加费。
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 具有以正确顺序评估所有规则的概念,因此它将 "know" 将规则应用于国家/地区,然后再将它们用作收费规则的输入。
这只是我正在玩的一个简化示例,所以它似乎不应该这么复杂,所以我的概念方法有误吗?
哦,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.- 创建一个 class 来模拟约束和结果:
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
希望对您有所帮助,