I tried researching a lot online but unable to find the exact reason for my error
Here is my problem
I am trying to write an if-else condition in RHS (THEN) but my drools show the following error
[An error occurred when attempting to build drools rule set. Error: Unable to Analyse Expression if (
I know this clearly says that I can't write if inside THEN (RHS), but I was able to do it in drools version 6.5.0-FINAL
is it something that got introduced in the 6.5.0 version? please guide me in the right direction for this investigation
I cant create two rules for this I need an if-else condition inside THEN
my drools version is 5.5.0
rule "TEST"
when
$aa : Age()
then
if(//something)
{
//something
}
else
{
}
end
This is perfectly valid going back to Drools 5.0 (can't speak to earlier, that's the earliest I ever used.) It is bad rule design -- whatever is restricting you to not adding a second rule is simply incorrect -- but you can have an if/else on the right hand side.
The reason it is bad rule design is that conditions should go on the conditional clause (left hand side, 'when') and the right hand side (then) should have the consequences. Drools optimizes the checking of conditions on the LHS, but executes the consequences on the RHS as-is. So by moving conditions to the RHS, you are causing your rules to be less performant because you're bypassing the optimization Drools provides.
The correct way would be -- as you probably figured out -- to have two rules like follows. (Since I don't know your particular use problem I'm going to make up something -- a difference in consequence depending on if the age is greater than or less than 18.)
rule "TEST - Under 18"
when
Age( value < 18 )
then
System.out.println("User is underage.");
end
rule "TEST - Adult"
when
Age( value >= 18 )
then
Sytem.out.println("User is an adult.");
end
As mentioned, you still can use an if-else if you must, but it is bad rule design and if I were doing your code review I'd send it back for revision. :)
rule "TEST WITH BAD PRACTICES"
when
Age( $age: value )
then
if ($age < 18) {
System.out.println("User is underage.");
} else {
System.out.println("User is an adult.");
}
end
This rule is perfectly valid and it works. If it doesn't work for you, the problem is not with the rule, it's with something else in how you're loading or firing your rules that you have not shared. Maybe it's your dialect. Maybe it's how you're loading them. Maybe you have a typo in your 'if' like a missing quotation mark or hyphen, which you haven't shown us because you've not provided your actual rule.
That's something you'll have to investigate in your own environment (I suggest breakpoints and a debug session in your IDE.)
For completeness' sake, Drools 7 introduced the concept of conditional and named consequences. While many I know prefer the simplicity and streamlined-ness of the best practice of having multiple rules, this is an alternative way to provide conditional processing in a single rule.
Basically the idea is that if you have two extremely similar conditions, such that one builds off the other, you can use a syntax that is very similar to "goto" to trigger permutations of the right hand side. Here is how you might go about doing it for your situation:
rule "TEST with named consequences"
when
Age( $age: value )
if ( $age < 18 ) break[underage]
then
System.out.println("User is an adult.");
then[underage]
System.out.println("User is underage.");
end
Related
i was wondering if i can perform a contains operation on the left hand side (LHS) on a drools rule.
Something of the sort:
global java.util.List myGlobalList;
dialect "mvel"
rule "checker"
when
Task() from myGlobalList
then
System.out.println(myGlobalList);
end
The example above is not a working one and im not quite sure how to make it work. I am open to suggestions with other keywords from drools (contains, exists, in)!
Only if you want to check the global's initial state. Generally, globals are out of scope of what the rule is aware of. Your rules won't be cognizant of any changes to the the global.
You should instead put your series of tasks in a list in working memory like this:
rule "checker"
when
$myTasks: List() // suggest not a raw list in working memory, but this "works"
Task() from $myTasks
then
System.out.println($myTasks);
end
Your rule, as-is, will only work if Task is present in your global list at the time the rules are fired. If a rule subsequently removes the task, that won't be visible. There's also some additional weirdness around visibility that I don't fully understand myself because you shouldn't be writing rules against globals anyway.
In theory, if you understand the Drools lifecycle -- especially how the matcher phase works and how you can re-trigger that phase based on actions in your rules (update, insert, etc.) -- you chould in theory write rules like this that key off of the global. But since the global isn't part of working memory, it can't be a party to those same actions (eg you can't call update(myGlobalList)). This also adds a lot of complexity because future maintainers of your rules will need the same understanding of the lifecycle ... it'll become a maintenance nightmare, basically.
At the end of the day, you really shouldn't be using globals at all. They're usually a code smell more than anything, it's how we used to get data out of the rules back in the "old days" (10 plus years ago), because there weren't really any better ways and we didn't know any better. They're really analogous to 'static' variables in Java -- if you've got multiple threads, you can't rely on the value in a static non-volatile variable in 'if' conditions.
So the answer to your question is -- technically yes, but practically no. Don't do it. Design your rules better.
Note that the Drools documentation warns you not to do this as well:
Do not use global variables to establish conditions in rules unless a global variable has a constant immutable value. Global variables are not inserted into the working memory of the Drools engine, so the Drools engine cannot track value changes of variables.
Do not use global variables to share data between rules. Rules always reason and react to the working memory state, so if you want to pass data from rule to rule, assert the data as facts into the working memory of the Drools engine.
Basically the only time you'd ever reference a global on the left hand side ("when") is when the global is acting as a constant. So something like this:
global Float freeShippingMinimum;
rule "Free shipping if minimum met"
when
$c: Cart( subtotal >= freeShippingMinimum,
shippingFee > 0.0 )
then
modify( $c ) {
setShippingFee( 0.0 )
}
end
In this example, you get free shipping if your subtotal meets a minimum threshold. That threshold is passed into the rules because it is a constant and it comes from some external data source. It's passed into the rules as a global because it is a constant; since it is a constant, we can refer to it on the left hand side / "when".
I'm using an AgendaFilter to decide whether a rule activation should be executed or not.
As part of my working memory's facts I insert one "rule configuration" fact per rule which contains how often my rule is allowed to be executed (and a corresponding counter).
I noticed that Match.getFactHandles() only returns the facts that 'created this match' (as per java doc).
Is there a way to access the WorkingMemory and all its facts or do I basically have to declare my "rule configuration" fact as part of my condition?
Example to illustrate: right now I do something like this (below) and I wonder if I can get around having to declare the $ruleConfig fact in the rule but still be able to look it up in my AgendaFilter.
rule "abc"
#uid("1234")
when
$ruleConfig : RuleConfig(uid="1234")
// insert the actual rule conditions
...
Thanks!
(I know I could solve this with control facts entirely inside the rule, but for architectural reasons I want to keep this out of the actual rule code as much as possible, hence the AgendaFilter)
An AgendaFilter is a Pojo, and you can create it with the KieSession being passed as an argument. This lets you access all the WM facts, according to the API documentation. Thus, it isn't necessary to have the appropriate RuleConfig as an extra condition with each rule. The only advantage of your approach is that you have this object readily available in the List of matched facts.
But it would be just as simple to pass a Map<String,RuleConfig> to te AgendaFilter, without all of the RuleConfig objects being added to the Working Memory.
A slightly more sophisticated approach would be
rule "abc"
#uid("1234")
when
$ruleConfig : RuleConfig(uid="1234", counter > 0)
// ...
with the counter being decremented with each rule firing - not necessarily on each RHS but in a central place: a
RuleRuntimeEventListener.
Both require and assert are used to perform certain checks during runtime to verify certain conditions.
So what is the basic difference between them?
The only one I see is that require throws IllegalArgumentException and assert throws AssertionError.
How do I choose which one to use?
As Kigyo mentioned there is a semantic difference
assert means that your program has reached an inconsistent state this might be a problem with the current method/function (I like to think of it a bit as HTTP 500 InternalServerError)
require means that the caller of the method is at fault and should fix its call (I like to think of it a bit as HTTP 400 BadRequest)
There is also a major technical difference:
assert is annotated with #elidable(ASSERTION)
meaning you can compile your program with -Xelide-below ASSERTION or with -Xdisable-assertions and the compiler will not generate the bytecode for the assertions. This can significantly reduce bytecode size and improve performance if you have a large number of asserts.
Knowing this, you can use an assert to verify all the invariants everywhere in your program (all the preconditions/postconditions for every single method/function calls) and not pay the price in production.
You would usually have the "test" build with all the assertions enabled, it would be slower as it would verify all the assertions at all times, then you could have the "production" build of your product without the assertions, which you would eliminate all the internal state checks done through assertion
require is not elidable, it makes more sense for use in libraries (including internal libraries) to inform the caller of the preconditions to call a given method/function.
This is only my subjective point of view.
I use require whenever I want a constraint on parameters.
As an example we can take the factorial for natural numbers. As we do not want to address negative numbers, we want to throw an IllegalArgumentException.
I would use assert, whenever you want to make sure some conditions (like invariants) are always true during execution. I see it as a way of testing.
Here is an example implementation of factorial with require and assert
def fac(i: Int) = {
require(i >= 0, "i must be non negative") //this is for correct input
#tailrec def loop(k: Int, result: Long = 1): Long = {
assert(result == 1 || result >= k) //this is only for verification
if(k > 0) loop(k - 1, result * k) else result
}
loop(i)
}
When result > 1 is true, then the loop was executed at least once. So the result has to be bigger or equal to k. That would be a loop invariant.
When you are sure that your code is correct, you can remove the assert, but the require would stay.
You can see here for a detailed discussion within Scala language.
I can add that, the key to distinguish between require and assert is to understand these two. These two are both tools of software quality but from different toolboxes of different paradigms. In summary assert is a Software testing tool which takes a corrective approach, whereas require is a design by contract tool which takes a preventive approach.
Both require and assert are means of controlling validity of state. Historically there were 2 distinct paradigms for dealing with invalid states. The first one which is mainstream collectively called software testing discipline methodologies and tools. The other, called design by contract. These are two paradigms which are not comparable.
Software testing ensures a code versatile enough to be capable of error prone actions, were not misused. Design by contract controls code from having such capability. In other words Software testing is corrective, and design by contract is preventive.
assert is used to write unit tests, i.e. if a method passes all tests each written by an assert expression, the code is qualified as error free. So assert seats besides operational code, and is an independent body.
require is embedded within code and part of it to assure nothing harmful can happen.
In very simple language:
Require is used to enforce a precondition on the caller of a function or the creator of an object of some class. Whereas, assert is used to check the code of the function itself.
So, if a precondition fails, then you get an illegal argument exception. Whereas, if an assertion fails and it's not the caller's fault and consequently you get an assertion error.
require, ensure and invariance are concepts in Contract By Design (CBD) development process.
require checks for the pre-conditions that the caller should satisfy to consume the routine.
ensure checks for the correctness in the return value (and to also verify only the desired change has happened and nothing more)
invariance checks for the validness of the class at all critical times.
CBD is a development methodology to build correct/robust software. For more details on CBD Google and you should hit a link from Eiffel Software. Hope this helps.
Scaladocs/javadocs are pretty good as well:
assert()
Tests an expression, throwing an AssertionError if false. Calls to this method will not be generated if -Xelide-below is greater than ASSERTION.
require()
Tests an expression, throwing an IllegalArgumentException if false. This method is similar to assert, but blames the caller of the method for violating the condition.
For example, if I implement some simple object caching, which method is faster?
1. return isset($cache[$cls]) ? $cache[$cls] : $cache[$cls] = new $cls;
2. return #$cache[$cls] ?: $cache[$cls] = new $cls;
I read somewhere # takes significant time to execute (and I wonder why), especially when warnings/notices are actually being issued and suppressed. isset() on the other hand means an extra hash lookup. So which is better and why?
I do want to keep E_NOTICE on globally, both on dev and production servers.
I wouldn't worry about which method is FASTER. That is a micro-optimization. I would worry more about which is more readable code and better coding practice.
I would certainly prefer your first option over the second, as your intent is much clearer. Also, best to keep away edge condition problems by always explicitly testing variables to make sure you are getting what you are expecting to get. For example, what if the class stored in $cache[$cls] is not of type $cls?
Personally, if I typically would not expect the index on $cache to be unset, then I would also put error handling in there rather than using ternary operations. If I could reasonably expect that that index would be unset on a regular basis, then I would make class $cls behave as a singleton and have your code be something like
return $cls::get_instance();
The isset() approach is better. It is code that explicitly states the index may be undefined. Suppressing the error is sloppy coding.
According to this article 10 Performance Tips to Speed Up PHP, warnings take additional execution time and also claims the # operator is "expensive."
Cleaning up warnings and errors beforehand can also keep you from
using # error suppression, which is expensive.
Additionally, the # will not suppress the errors with respect to custom error handlers:
http://www.php.net/manual/en/language.operators.errorcontrol.php
If you have set a custom error handler function with
set_error_handler() then it will still get called, but this custom
error handler can (and should) call error_reporting() which will
return 0 when the call that triggered the error was preceded by an #.
If the track_errors feature is enabled, any error message generated by
the expression will be saved in the variable $php_errormsg. This
variable will be overwritten on each error, so check early if you want
to use it.
# temporarily changes the error_reporting state, that's why it is said to take time.
If you expect a certain value, the first thing to do to validate it, is to check that it is defined. If you have notices, it's probably because you're missing something. Using isset() is, in my opinion, a good practice.
I ran timing tests for both cases, using hash keys of various lengths, also using various hit/miss ratios for the hash table, plus with and without E_NOTICE.
The results were: with error_reporting(E_ALL) the isset() variant was faster than the # by some 20-30%. Platform used: command line PHP 5.4.7 on OS X 10.8.
However, with error_reporting(E_ALL & ~E_NOTICE) the difference was within 1-2% for short hash keys, and up 10% for longer ones (16 chars).
Note that the first variant executes 2 hash table lookups, whereas the variant with # does only one lookup.
Thus, # is inferior in all scenarios and I wonder if there are any plans to optimize it.
I think you have your priorities a little mixed up here.
First of all, if you want to get a real world test of which is faster - load test them. As stated though suppressing will probably be slower.
The problem here is if you have performance issues with regular code, you should be upgrading your hardware, or optimize the grand logic of your code rather than preventing proper execution and error checking.
Suppressing errors to steal the tiniest fraction of a speed gain won't do you any favours in the long run. Especially if you think that this error may keep happening time and time again, and cause your app to run more slowly than if the error was caught and fixed.
Why doesn't SQL Server support TRY-CATCH blocks inside UDFs?
If we're talking about scalar UDFs, which are mostly used for calculations and conversations, this block should be heavily used, but we don't have it.
Also, what workarounds do you use for this?
UDFs in MSSQL are not allowed to have side effects, which BOL defines as "changing the database state". That's a rather vague description, but MSSQL apparently considers errors to change the database state - this UDF doesn't compile:
create function dbo.foo()
returns int
as
begin
raiserror('Foo', 16, 1)
return 1
end
go
The error message is:
Msg 443, Level 16, State 14, Procedure
foo, Line 5 Invalid use of a
side-effecting operator 'RAISERROR'
within a function.
If raising an error is considered to change the database state, then trapping and handling one presumably is too. Which is not much of an explanation, I admit.
In practical terms, though, it's often best to let the caller decide how to handle errors anyway. Say you write a function like this:
create function dbo.divide (#x int, #y int)
returns float
as
begin
return #x / cast(#y as float)
end
How would you handle the case where an application passes zero for #y? If you catch the divide by zero exception, what are you going to do next? What value can you return from the function that makes sense to the caller, bearing in mind that you may not even know which application is calling your function anyway?
You might think of returning NULL, but would the application developers using your function agree? Do all their applications consider a divide by zero error to have the same impact or importance? Not to mention that NULLs in certain places can completely change the results of a query, perhaps in ways that the application developer doesn't want at all.
If you're the only developer, maybe it isn't an issue, but with more people it quickly becomes one.
Maybe it is because the overhead is too much - a scalar function could be called on a column as part fof a select and so be called thousands of times. If there was a reasonable overhead to allow try/catch it would slow it down horrendously.
As a work around, I would call the UDF from TRY/CATCH inside a stored procedure.
With SQLServer 2012, you can try exec sp_your_procedure_with_try_catch, it worked for me.
Actually several of my triggers have the logics in one key SP. I didn't know try-catch is not allowed in UDF, until I tried to rewrite some of them without the SP.