I have 2 collections of the same type and each object in the collection is key by an id. My goal is to find the same object in both collections and then compare a field against each other. If they are not the same field then store the differences.
My issue is performance, for every rule I re-scan the collection for the same object. Is there a way if the object matches then run all field validations instead of finding the item in the collection multiple times?
Fact Code:
public class ReconcilerFact
{
private List<Security> securitySystem1;
private List<Security> securitySystem2;
public ReconcilerFact(List<Security> securities1, List<Security> securities2)
{
this.securitySystem1 = securities1;
this.securitySystem2 = securities2;
}
public List<Security> getSecuritySystem1()
{
return securitySystem1;
}
public List<Security> getSecuritySystem2()
{
return securitySystem2;
}
}
Drools Code:
rule "ISIN Rule"
no-loop
when
## conditions
##
$recon : ReconcilerFact()
$security1 : Security() from $recon.securitySystem1
$security2 : Security(sSecId == $security1.sSecId, sISIN != $security1.sISIN) from $recon.securitySystem2
then
## For the valid condition
##
result.add($security1, SecurityFields.ISIN, $security1.getsISIN(), $security2.getsISIN());
end
rule "Cusip Rule"
no-loop
when
## conditions
##
$recon : ReconcilerFact()
$security1 : Security() from $recon.securitySystem1
$security2 : Security(sSecId == $security1.sSecId, sCusip != $security1.sCusip) from $recon.securitySystem2
then
## For the valid condition
##
result.add($security1, SecurityFields.CUSIP, $security1.getsCusip(), $security2.getsCusip());
end
rule "Sedol Rule"
no-loop
when
## conditions
##
$recon : ReconcilerFact()
$security1 : Security() from $recon.securitySystem1
$security2 : Security(sSecId == $security1.sSecId, sSedol != $security1.sSedol) from $recon.securitySystem2
then
## For the valid condition
##
result.add($security1, SecurityFields.SEDOL, $security1.getsSedol(), $security2.getsSedol());
end
Instead of using the from Conditional Element you can just insert all the security objects and tag them with a Group field. So you will end up having:
$s1: Security(group == "Group1")
$s2: Security(group == "Group2", sSecId == $security1.sSecId)
That will treat each security as a fact and if you modify one single instance, only that instance will be reevaluated.
Cheers
Related
I have 2 agents of different type.
[Person(type) owner(agent) 1(parameter) Carlink(connection)]
[Vehicle(type) car(agent) 1(parameter) OwnerLink(connection)]
I want to link them if parameter "1" of the owner is same to parameter "1" of the car.
I'm thinking adding this statement on startup on Vehicle(type)
OwnerLink.connectto("condition")
What syntax should I need to add on the "condition" part.
Thanks in advance.
My understanding is that you have two populations: owners and cars. You also have a parameter called 1 in each (which is an int? double?). You also want to create single bidirectional links. If so, your code would be as follows:
for( Person p : owners) {
for( Vehicle v : cars) {
if( p.1 == v.1) {
p.Carlink.connectTo(v);
break;
}
}
}
If you may have multiple links, remove break;, also if you parameter is of type String, replace == v.1 with .equals(v.1).
To place the code in vehicle startup:
for( Person p : owners) {
if( p.1 == 1) {
p.Carlink.connectTo(this);
break;
}
}
}
global java.util.List rules;
global java.util.Map ruleParamsMap;
global java.util.List invoiceRowIds;
function BigDecimal sum(List invoiceRowIdsValue, String docType) {
return RuleHelper.sum(invoiceRowIdsValue, docType);
}
rule "example"
when
Boolean(booleanValue == true) from rules contains "TestedValue"
$amount : Integer() from ruleParamsMap.get("amount")
$sum : BigDecimal() from sum(invoiceRowIds, "IV")
Boolean(booleanValue == true) from $sum.compareTo(BigDecimal.valueOf($amount)) <= 0
then
System.out.println("RUN");
end
Here is my rule and for some reason, it prints RUN twice.
Any ideas why?
I have created two different rules, which belong to two different agenda-groups.
First one:
rule "32-30-33.32"
dialect "java"
salience 0
agenda-group "32-30"
when
map : Map((this["Product Name"].toUpperCase().contains("PREMIUM ADPRODUCT")) && ((this["Size Length"] != 5) || (this["Size"].toUpperCase() not contains "300X600") || (this["Size"].toUpperCase() not contains "280X130") || (this["Size"].toUpperCase() not contains "300X250") || (this["Size"].toUpperCase() not contains "970X250") || (this["Size"].toUpperCase() not contains "320X50")));
then
JSONObject jObject = new JSONObject("{\"error34\":\"Premium Adproduct doesn't contain required Creative size!\"}");
Iterator<?> keys = jObject.keys();
while(keys.hasNext()) {
String key = (String)keys.next();
Object value = jObject.get(key);
map.put(key, value);
}
debug(drools);
end
Another rule, in another agenda group:
rule "47-37-1.0"
dialect "java"
salience 0
agenda-group "47-37"
when
map : Map((this["OrderName"] == null));
then
JSONObject jObject = new JSONObject("{\"error1\":\"OrderName should not be null \"}");
Iterator<?> keys = jObject.keys();
while(keys.hasNext()) {
String key = (String)keys.next();
Object value = jObject.get(key);
map.put(key, value);
}
debug(drools);
end
After this, I set focus to the group "47-37",
kieSession.getAgenda().getAgendaGroup("47-37").setFocus();
All rules within the group "32-30" are also getting evaluated. I'm using Drools 7.0.0. How can I control execution of rules only within the focused group?
facing problem with List iteration in drools
GoodsShipment has the list of GoodsItems and
GoodsItem has the list of Documents
my requirement is, need to check atleast one document is available or no.
iam tried this
but failed
writen a class to checking purpose
public class CheckDocument {
public boolean flag = false;
public CheckPreviousDocument() {
}
public boolean getPreviousDocument(GoodsShipment goodsshipment) {
List<GoodsItem> list = goodsshipment.getGoodsItems();
Iterator<GoodsItem> itr = list.iterator();
while (itr.hasNext()) {
GovernmentAgencyGoodsItem document = itr.next();
if (document.getDocuments().size() > 0) {
flag = true;
break;
}
}
return flag;
}
}
rule "previousDocuments minimum 1"
when
$o: GoodsShipment()
%x: CheckPreviousDocuments(previousDocuments($o) == false)
then
insert(-------------)
end
can anyone please help me..
thanks in advance
Your code is somewhat unusual, but thus rule should do. Note that I have used Document as the type for the elements in the list returned by GovernmentAgencyGoodsItem.getDocuments().
rule atLeastOne
when
$gs: GoodsShipment()
List( size > 0 )
from accumulate ( $gi: GoodsItem() from $gs.getGoodsItems() and
$d: Document() from $gi.getDocuments();
collectList( $d ) )
then
// $gs contains at least one Document
end
The the following logic:
if (order.getPrice()<200 ) {
order.setPrice(order.getPrice()-10);
} else {
order.setPrice(order.getPrice()-20);
if (order.getPrice()<200 ) {
//do nothing
}else {
order.setFreeShip("true");
}
}
for above logic, if I want to implement in drools rule.
rule "rule 1"
when
$o:Order ( amount<200);
then
$o.setPrice($o.getPrice()-10);
end
rule "rule 2"
when
$o:Order (amount>200);
then
$o.setPrice($o.getPrice()-20);
end
If the fact's price is 210, the rule2 is activated then the rule1 will be fired. That is not expected. I don't want to retract(). So is there any better solution for this issue?
And can I specify the sequential rule once a rule is executed like a token mechanism.
Thanks.
No, you can't specify sequential for just one rule or group of rules. You'll need to create a flag and use it as a guard, for example:
rule "rule 1"
when
$o:Order ( amount<200);
not: Flag(object=$o)
then
$o.setPrice($o.getPrice()-10);
insert( new Flag($o) );
end
rule "rule 2"
when
$o:Order (amount>200);
not: Flag(object=$o)
then
$o.setPrice($o.getPrice()-20);
insert( new Flag($o) );
end
and
public class Flag {
private final Object object;
public Flag(Object o) {
this.object = o;
}
//add getter for object
//delegate equals and hashcode to object
}
rule "NYuser_Rule"
no-loop true
ruleflow-group "EvalLoopcondition"
when
m:HelloProcessModel(userlocation in ("NewYorkUser"), count < 4)
then
m.setLoopcondition(6);update(m);
end
rule "ChileUser_Rule"
no-loop true
ruleflow-group "EvalLoopcondition"
when
m:HelloProcessModel(userlocation in ("ChileUser"), count < 3)
then
m.setLoopcondition(5);update(m);
end
Something like this can help you out.