Tutorials

Java Training, Drools Training, Spring Training, Weekend Training, and Midweek 5 day IT Training Courses in London, Birmingham, Leicester, 
				 Leeds, Manchester and Carlisle. Training in Java, Java Enterprise, JEE, J2EE, C, Spring, Spring MVC, 
				 Spring Webflow, Objective-C, Drools

Drools Expert

Creating the Marriage Rules

So far we've processed the Birth and Baptism records, now let's move on to the Marriage Records

Let's start simple and then add to it

MarriageRecords.drl

Review the Code

If we look at the code we can see that we perform the following

Criteria

  • Marriage Record
    • determine the name of the first person
    • determine the name of the second person
    • determine the marriage date
    • determine the marriage location
  • Person Records
    • identify a person with the same name as the first person in the Marriage Record
    • identify a person with the same name as the second person in the Marriage Record
    • ensure that neither person is already married

Consequence

  • Relationships
    • create a MARRIEDTO relationship from person1 to person2
    • create a MARRIEDTO relationship from person2 to person1
    • create a MARRIED Event for the marriage date
  • Modifying the Records
    • Modify the Person1 record and add the relationship and event
    • Modify the Person2 record and add the relationship and event

Modify or Update?

One thing that is worth mentioning here is that we have used the modify keyword instead of update. What is the difference?

If we refer to the Drools Documentation we can see that:

When you call modify() (see the modify statement section) on a given object it will trigger a revaluation of all patterns of the matching object type in the knowledge base. This can can lead to unwanted and useless evaluations and in the worst cases to infinite recursions. The only workaround to avoid it was to split up your objects into smaller ones having a 1 to 1 relationship with the original object.

This feature allows the pattern matching to only react to modification of properties actually constrained or bound inside of a given pattern. That will help with performance and recursion and avoid artificial object splitting.

By default this feature is off in order to make the behavior of the rule engine backward compatible with the former releases. When you want to activate it on a specific bean you have to annotate it with @PropertyReactive.

In layman's terms, if we add the annotation @PropertyReactive to Person.java, we can tell the Rule Engine not to re-evaluate a Rule against a Fact if the field that is modified is not in the criteria.

In this case, we modify the Events and the Relationships for the Person records, but we do not consider those in the Criteria so the rule will not re-fire.

Infact, in this event, we are only adding this information so that the TreeBuilder can add the wives to the family tree. So, let's uncomment the line we commented out in TestRuleRunner and run the test again:

TestRuleRunner.java

If we now run the test, we can see that our test passes and our console output is as follows:

We can clearly see the wives are now presented and all we have done is add one more simple rule.

Removing the Oops Factor!

Our rule works fine, but as it stands, it would be possible for both father and son to marry the same women as we have missed a few important checks:

  • Is the age difference between husband and wife unrealistic - say 200 years?
  • Would either of these people have been too young to marry on the wedding day?
  • Were both people actually born?
  • Are the people the same sex? Perhaps not a problem now, but might have raised a few eyebrows in the 1700s!

As you can see, our rule was not very comprehensive - so let's look at how we can modify our rule to include the missing criteria

Adding the SimpleFacts

First we need 3 more simple facts as follows

  • minAgeToMarry - Period(0,0,18) - 18 years
  • maxAgeToMarry - Period(0,0,40) - 40 years
  • maxMarriedAgeDifference - Period(0,0,2) - 2 years

We need to add these to the testFactsInserted method in our TestRuleRunner and then insert them into the Rule Engine as follows:

With those inserted, we now need to update the Rule. I will include the whole rule and then go through the changes.

Review the Rule

Let's walk through the rule line by line:

  • SimpleFacts
    • First we expose the 3 new SimpleFacts that we have inserted into the Rule Engine
  • MarriageRecord
    • The MarriageRecord criteria remains the same, I have changed the date variable to $marriagedate to make the rule clearer
  • Partner1 (Person)
    • the rule ensures that this person is male
    • a birth record must exist for this person
    • on the wedding date the person must be at least min age to be marry
    • on the wedding date the person must be less than max age to marry
    • the person must not be married already
  • Partner2 (Person)
    • the rule ensures that this person is female
    • a birth record must exist for this person
    • on the wedding date the person must be at least min age to be marry
    • on the wedding date the person must be less than max age to marry
    • person2 must be less than maxAgeDifference years older than person1
    • person2 must be less than maxAgeDifference years younger than person1
    • the person must not be married already

The rest of the rule remains the same.

Run the TestRuleRunner

Wow. What happened?

Jack Doe has lost his wife!

A quick check will reveal that this is because Jack is more than 2 years older than Jane.

If we want to allow this marriage, we need to increase the maxMarriedAgeDifference SimpleFact to 3 years in the TestRuleRunner. Give that a go and we can see that our test now works fine and our rule is much more comprehensive.

In our next tutorial we will start running the rules with files of real data.

TRAINING & CONSULTANCY

Java, JEE, Drools, Spring and so much more.