Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write nested conditions in when in drools

Tags:

drools

Here is my JSON Document

    {
   "location": {
      "details": [
         {
            "country": "India",
            "state": "haryana"
         },
         {
            "country": "America",
            "state": "LA"
         },
         {
            "country": "India",
            "state": "Maharashtra"
         }
      ]
   },
   "organisation": {
      "details": [
         {
            "name": "AON",
            "country": "india"
         },
         {
            "name": "AON",
            "country": "America"
         }
      ]
   }
}

I have to apply a rule in Below format

 If(

        (location.details.country=='India' OR 
        location.details.state=='haryana') 
AND 

        organisation.details.name=='AON'
    )

Till now i have researched and know that rules on the fields of the same class can be applied in nested format like below. in this link : How to write nested conditions in when in drools

// Use this instead
Person( ( age > 50 && weight > 80 ) || height > 2 )

But i want to apply rules of different pojo class in the same nested condition as below

    If(

                (location.details.country=='India' OR 
                location.details.state=='haryana') 
        AND 

                organisation.details.name=='AON'
      AND 
               (location.details.country=='India' AND
                organisation.details.country=='India')
            )
//any level of nested between different pojo classes can be present

Is this possible to do in drools?

I have written following rule

rule "rule1"
salience 1
when


        $rootDoc:RootDoc($locationList:location && $organisationList:organisation) 

     and
        (
            $orgList:Organisation($orgdetailsList:details) from $organisationList
            NamesList1:Details(name=='AON') from $orgdetailsList
            or
            $locList:Location($locdetailsList:details) from $locationList
            NamesList2:Details_(state=='haryana') from $locdetailsList

        )

then
    System.out.println("Pojo Welocome-------");



end

But its showing me this error : Line 18:3 mismatched input 'NamesList1' in rule "rule1"

Basically when i write two conditions in same bracket it is showing me error.

Below are the pojo Classes

-----------------------------------pojo_Classes2.Detail.java-----------------------------------

package pojo_Classes2;

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"name",
"country"
})
public class Detail {

@JsonProperty("name")
private String name;
@JsonProperty("country")
private String country;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("name")
public String getName() {
return name;
}

@JsonProperty("name")
public void setName(String name) {
this.name = name;
}

@JsonProperty("country")
public String getCountry() {
return country;
}

@JsonProperty("country")
public void setCountry(String country) {
this.country = country;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
-----------------------------------pojo_Classes2.Detail_.java-----------------------------------

package pojo_Classes2;

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"country",
"state"
})
public class Detail_ {

@JsonProperty("country")
private String country;
@JsonProperty("state")
private String state;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("country")
public String getCountry() {
return country;
}

@JsonProperty("country")
public void setCountry(String country) {
this.country = country;
}

@JsonProperty("state")
public String getState() {
return state;
}

@JsonProperty("state")
public void setState(String state) {
this.state = state;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
-----------------------------------pojo_Classes2.Location.java-----------------------------------

package pojo_Classes2;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"details"
})
public class Location {

@JsonProperty("details")
private List<Detail_> details = null;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("details")
public List<Detail_> getDetails() {
return details;
}

@JsonProperty("details")
public void setDetails(List<Detail_> details) {
this.details = details;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
-----------------------------------pojo_Classes2.Organisation.java-----------------------------------

package pojo_Classes2;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"details"
})
public class Organisation {

@JsonProperty("details")
private List<Detail> details = null;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("details")
public List<Detail> getDetails() {
return details;
}

@JsonProperty("details")
public void setDetails(List<Detail> details) {
this.details = details;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
-----------------------------------pojo_Classes2.RootDoc.java-----------------------------------

package pojo_Classes2;

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"organisation",
"location"
})
public class RootDoc {

@JsonProperty("organisation")
private Organisation organisation;
@JsonProperty("location")
private Location location;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("organisation")
public Organisation getOrganisation() {
return organisation;
}

@JsonProperty("organisation")
public void setOrganisation(Organisation organisation) {
this.organisation = organisation;
}

@JsonProperty("location")
public Location getLocation() {
return location;
}

@JsonProperty("location")
public void setLocation(Location location) {
this.location = location;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

I think i have found the problem.

Is it right?

This is happening because you can't bind a variable and use it in RHS if the condition is OR between them.???

like image 468
gaurav9620 Avatar asked Sep 10 '18 16:09

gaurav9620


People also ask

How do you use salience in drools?

Setting a Priority Salience is a keyword in the . drl file that we can assign a positive or negative number. The number determines the salience priority. A higher number denotes a higher priority, so rules with a higher salience will be executed first by the Drools engine.

What is Drools Rule Engine used for?

Drools Rule Engine is a rule-based approach to implement an Expert system in the Drools software. The Rule engine provides Expert systems which are knowledge-based systems that help you to make decisions like what to do and how to do it. It gathers knowledge into a knowledge base that can be used for reasoning.

How does drools work in Java?

Drools is a library and rules engine in Java that lets you add business rules (logic) separate from other code in the system. This is an overview and introduction.


Video Answer


1 Answers

Yes, this is totally possible.

For simplicity, I have assumed that the object you've put into working memory is structured like this:

class Data {
  Location location;
  Organization organization;
}

With subsidiary classes defined as follows:

class Location {
  List<Detail> details;
}
class Organization {
  List<Detail> details;
}
class Detail {
  String name;
  String country;
  String state;
}

This should accurately model the JSON in your question. The getters and setters from these classes are omitted for brevity.

Now, our goal is to write a rule that triggers when there exists a Detail within Location that has both country = "India" and state = "Haryana"; as well there exists a Detail within Organization that has name = "AON".

We can accomplish this as follows:

rule "Trigger when Haryana, India is a Location and AON is an Organization name"
when
  // First we need to extract the location and organization so we can do work on them
  Data( $location: location != null,
        $organization: organization != null )

  // Confirm that there exists an organization detail with name = "AON"
  Organization( $orgDetails: details != null ) from $organization
  exists( Detail( name == "AON" ) from $orgDetails )

  // Confirm that there exists a location with country = India and state = Haryana
  Location( $locDetails: details != null ) from $location
  exists( Detail( country == "India", state == "Haryana" ) from $locDetails )
then
  System.out.println("Rule has been executed")
end

I'm using the exists predicate because I'm just checking for the presence of these objects that meet the conditions. If we want to bind the identified objects to variables, you could simply do an assignment -- for example:

// This snippet matches the previous rule where we identify an Organization detail with name of "AON"
Organization( $ordDetails: details != null ) from $organization
$aon: Detail( name == "AON" ) from $orgDetails

Or even assign properties themselves:

// This snippet matches the previous rule where we identify the Location detail for Haryana, India
Location( $locDetails: details != null ) from $location
Detail( country == "India",
        state == "Haryana",
        $name: name ) from $locDetails

I'm not very familiar with Jackson's binding libraries, but from what I can understand of the POJOs you posted, the syntax should be very similar, if not identical, for the objects you're working with directly. (Your "RootDoc" and my "Data" are effectively the same thing, from what I can tell.)

Anyway, this works because Drools evaluates all of the left hand side conditions in order to decide whether the rule should be triggered. So if we look at our example rule, it checks that there exists a Detail inside of Organization that meets our condition (has name of "AON"). If this condition is not met, the rule does not trigger because the left hand side has at that point evaluated as 'false'. If it does exists, we then check to see if there is a detail inside of Location that meets our condition (that has both country = India and state = Haryana). This rule will only be triggered when all conditions on the left hand side are met; it is a set of "naturally" anded conditions.

I think it is worth pointing out that one must check both country = India and state = Haryana inside of the same predicate. Otherwise it might end up in a condition where you have two Details that each has half of the condition, but no one Detail that has both. For example, you might have a Detail where country is null but state is Haryana, and a Detail where country is India and state is Maharashtra; if you do not have both checks in the same predicate, this scenario might trigger the rule even though you have no one Detail that meets both conditions.

like image 100
Roddy of the Frozen Peas Avatar answered Oct 19 '22 04:10

Roddy of the Frozen Peas