The most basic use of from clause is not working, even when I know there are elements in the list and there is no conditions for the elements being extracted from that list, and I have other rules working properly.
Here is what happens, there are many variables in my problem, but I have simplified to this:
Having this two rules, the firstone is made to demostrate that fixedShipmentValueData list, has at least one element. However, the second rule isn't fired, even when the only different thing it does from the firstone, is to use the from clause and put a variable name.
rule "Print list value"
ruleflow-group "fixed-values"
no-loop
when
cParams: CustomerParameters(list: fixedShipmentValueData)
then
System.out.format("There are %s elements at fixedShipmentValue and fixed value is %s%n",list.size(),
((ParameterValues)list.get(0)).getFixedShipmentValue());
end
rule "Do something with the list"
ruleflow-group "fixed-values"
no-loop
when
cParams: CustomerParameters(list: fixedShipmentValueData)
ParameterValues($fixedShipmentValue: fixedShipmentValue) from list
then
System.out.format("fixed Shipment Value is %s%n", $fixedShipmentValue);
end
This looks so simple... I have expent enough time as to be out of ideas.
Without seeing the Java code for CustomerParameters, ParameterValues and the application part that creates, composes and inserts the fact(s) there's just one scenario I know that can reproduce the effect as you have told it. Consider this:
A List<Base> is field list in class X. There are subclasses SubA and SubB both extending Base. Create X, add objects of class SubA to list. A rule (like "Print list value") will show that the list is not empty.
However, a rule using a pattern such as
X( $list: list )
SubB() from $list
will never fire, since there are no SubB's in Base.list.
Related
I am new to Drools, we are trying to create basic validation rules like a NULL check, etc. using the Drools n Scala framework.
I have a source file which has 200 attributes, need to apply NULL-check rule on all these attributes,
is there any easy way to do this? or do I need to create 200 rules for each attribute?
Thanks in advance.
Assuming you have a POJO ("plain old java object", getters/setters and some private variables to hold values) or modern java Records (effectively the same thing), then the answer is no: you need separate rules. For this scenario, the only way to check that field "name" is null is to actually assert against that field like this:
rule "example - name is null"
when
ExampleObject( name == null )
then
System.out.println("Name is null.");
end
However there exist other data structures -- for example, Map and its sibling types -- where you can reference the fields by name. In this case you could theoretically iterate through all of the field names and find the one whose value is empty.
So, for example, Map has a keySet() method which returns a set of fields -- you could iterate through this keyset and for each key check that there is a non-null value present in the map.
rule "example with map"
when
$map: Map()
$keys: Set() from $map.keySet()
$key: String() from $keys
String( this == null ) from $map.get($key)
// or this might work, not sure if the "this" keyword allows this syntax:
// Map( this[$key] == null ) from $map
then
System.out.println($key + " is missing/null");
end
This would require converting your Java object into a Map before passing into the rules.
However I DO NOT RECOMMEND this approach. Maps are extremely un-performant in rules because of how they serialize/deserialize. You will use a ton of unnecessary heap when firing them. If you look at how a HashMap serializes, for example, by peeking at its source code you'll see that it actually contains a bunch of "child" data structures like entryset and keyset and things like that. When using "new", those child structures are only initialized if and when you need them; but when serializing/deserializing, they're created immediately even if you don't need them.
Another solution would be to use Java reflection to get the list of declared field names, and then iterate through those names using reflection to get the value out for that field. In your place I'd do this in Java (reflection is problematic enough without trying to do it in Drools) and then if necessary invoke such a utility function from Drools.
I have just started learning Drools and have written the following rule
rule "matematikk"
when
class( code == "MAT1003") or class( code == "MAT1008")
or
class( code == "REA3022") or class( code == "REA3024") or class( code == "REA3026") or class( code == "REA3028")
or
class(code == "MAT1006") and class(code == "MAT1010") or class( code == "MAT1001") and class( code == "MAT1005")
or
class(code == "MAT1002") or class(code == "MAT1007")
then
logger.info("passed");
end
when I run this rule I will get three passed prints in the terminal? which is correct since only three of the line are true, but how do I make it process the entire "when" block and after that go to the "then" section.
cheers,
ehsan
also if I remove the "or" between the lines I won't get any results.
Your rule doesn't really make sense. You've got "ands" and "ors" mixed up in here in no particular order. Setting things on separate lines doesn't create any sort of "grouping". Proximity similarly doesn't provide any sort of inherent relationship. The "and"s on the third 'line' are particularly confusing -- I have no idea what they're supposed to be and-ing.
Generally, if you want to represent an "or" condition, you'd write the conditional like this:
class( code in ("MAT1003", "MAT1008", ... ))
(Where "..." represents additional values.)
This is read as "There is a 'class' that has code MAT1003 or MAT1008."
For an "and" you'd simply have two different statements; only if both match will the rule be 'triggered'. For example:
exists(class(code == "MAT1006"))
exists(class(code == "MAT1010"))
This would trigger if there are at least 2 "class" instances in working memory, and there is at least one with code MAT1006 and at least one with code MAT1010.
I used exists because you don't actually need a reference to the matching instance for use in the right hand side; I also presumed you only need to trigger once regardless of how many instances matched your condition.
Finally -- I strongly suggest not naming your class "class" since it's a reserved word in Java. If it is representing some sort of educational class (eg at university), may I suggest calling it Course instead?
I am having an issue understanding RETE algorithm Beta node JoinNode and notNode?
Documentation says :
There are two two-input nodes, JoinNode and NotNode, and both are
types of BetaNodes. BetaNodes are used to compare 2 objects, and their
fields, to each other. The objects may be the same or different types.
By convention, we refer to the two inputs as left and right. The left
input for a BetaNode is generally a list of objects; in Drools this is
a Tuple. The right input is a single object. Two Nodes can be used to
implement 'exists' checks. BetaNodes also have memory. The left input
is called the Beta Memory and remembers all incoming tuples. The right
input is called the Alpha Memory and remembers all incoming objects.
I understood, Alpha Node: Various literal conditions for drl rules but above documentation for BetaNodes is confusing me a bit.
say below is drl condition for above diagram:
$person : Person( favouriteCheese == $cheddar )
Query: 1) what are these left and right inputs to two-input Beta Nodes exactly as explained in above documentation? I believe it's referring to facts and rules where I believe tuples would be facts?
2) notNode would be basically drl condition matching literal condition with not?
Updated question on 6Sep17:
3) I believe above diagram represent joinNode, how would notNode be represented , if above workflow is altered to suit notNode?
The condition corresponding to the diagram would be
Cheese( $name: name == "Cheddar" )
Person( favouriteCheese == $name )
Once there is a match, a new tuple consisting of the matching Cheese and Person is composed and can act as a new tuple for further matches if there is a third pattern in the condition.
A not-node would be one that asserts the non-existence of some fact. It would fire only once.
You might find a much better description of "rete" on the web.
How to check if the given value is a number in Prolog without using built-in predicates like number?
Let's say I have a list [a, 1, 2, 3]. I need a way to check if every element within this list is a number. The only part of the problem that bothers me is how to do the check itself without using the number predicate.
The reason why I'm trying to figure this out is that I've got a college assignment where it's specifically said not to use any of the built-in predicates.
You need some built-in predicate to solve this problem - unless you enumerate all numbers explicitly (which is not practical since there are infinitely many of them).
1
The most straight-forward would be:
maplist(number, L).
Or, recursively
allnumbers([]).
allnumbers([N|Ns]) :-
number(N),
allnumbers(Ns).
2
In a comment you say that "the value is given as an atom". That could mean that you get either [a, '1', '2'] or '[a, 1, 2]`. I assume the first. Here again, you need a built-in predicate to analyze the name. Relying on ISO-Prolog's errors we write:
numberatom(Atom) :-
atom_chars(Atom, Chs),
catch(number_chars(_, Chs), error(syntax_error(_),_), false).
Use numberatom/1 in place of number/1, So write a recurse rule or use maplist/2
3
You might want to write a grammar instead of the catch... goal. There have been many such definitions recently, you may look at this question.
4
If the entire "value" is given as an atom, you will need again atom_chars/2or you might want some implementation specific solution like atom_to_term/3 and then apply one of the solutions above.
I thought at first the compare option only appears for a test if the assertequals is between 2 strings, which makes sense. I believe i have also fired a failNotEquals(String1,String2) and the compare option comes up as well. I have done this when the object does not implement equals or perhaps i wish to compare for equality using my own rules and failing if that fails. However i have noticed a few times here and there sometimes failNotequals(String,String) does not enable the "compare" option. Am i missing something ???
CLARIFICATION of COMPARE option
The >compare< option is a menu option that is available when one right clicks on a failed junit item from the gui where it creates a tree with items for each "test". Often theres also a >print stack trace< option.
You get the "compare" option, when the end result of the test is a junit.framework.ComparisonFailure object. In that case you can see a visual comparison of the two objects (Strings for example) and check how they differ from each other.
Other types of results, such as a java.lang.IllegalAccessError, aren't parsed to that effect, as Eclipse doesn't know (and cannot deduce) that you were comparing two objects that lead to such a result, so it doesn't offer you the same visual boons.
I am not entirely sure what you mean by
failNotEquals does not enable the "compare" option
Here are a couple of thoughts.
failNotEquals takes three arguments, not two:
failNotEquals(message, expected, actual);
Even if strings would print out the same, they are NOT the same object. You need to tell JUnit how to compare them.
Consider this small, working test case.
import junit.framework.TestCase;
public class DemoTest extends TestCase {
public void testSomething() {
String a = "Hello";
assertTrue("Strings should be the same", "Hello".equals(a));
failNotEquals("Strings should be the same", "Hello", a);
}
}
The assertTrue works, but the failNotEquals does not.
The assertTrue is probably what you want. The "Hello".equals(a) will compare the strings properly. You can also use a equalsIgnoreCase here.
I'm guessing that the failNotEquals is probably close to what you are using. It fails with a java.lang.IllegalAccessError.