Parametrize the after operator in drools - drools

i have a fairly simple question, i have this rule
rule 'Rule1'
when
$inMess : MetaMessage()
not(MetaMessage(this after[0, 10000] $inMess, this != $inMess))
then
log.info("Message id:"+ $inMess.getId());
end
It works perfectly (in the after operand, if you use only a number it assumes milliseconds), i have only one other thing to do, parametrize the after operator so it can accept a property of the MetaMessage.
Something like this
rule 'Rule1'
when
$inMess : MetaMessage($delay : delay)
not(MetaMessage(this after[0, $delay] $inMess, this != $inMess))
then
log.info("Message id:"+ $inMess.getId());
end
Is there a way to do this?

Related

Drool DRL contains

This my When condition
$cla : cashliquidassets(
entity == "AU001",
asset_liability_indicator == "A",
product_group.contains('Loans','Bankofindia'),
product.contains("DS"),
counterparty_resident_indicator == "AU",
counterparty_type.contains("DS"),
related_entity == "Y"
)
I am getting an error at
Unable to Analyse Expression product_group.contains("Loans","Bankofindia")
Any Suggestions
Without your class model is hard to tell, but assuming that cashliquidassets.product_group is a String, you are trying to use an unexisting method String.contains(String, String).
One option would be to use an OR or and AND between 2 contains:
...
(product_group.contains('Loans') || product_group.contains('Bankofindia')),
...
or
...
product_group.contains('Loans'),
product_group.contains('Bankofindia'),
...
Another option could be to use the matches operator with a regular expression.
Hope it helps,

Drools MVEL Dialect - Semi-Colon Requirement

I am just curious as to why my Eclipse Drools compiler (6.5.0) requires semi-colons at the end of statements in the For loop, as below:
Map businessRulesRequest = $root.containsKey("BusinessRulesRequest") ? $root.get("BusinessRulesRequest") : null
Map quoteRequest = businessRulesRequest!=null && businessRulesRequest.containsKey("QuoteRequest") ? businessRulesRequest.get("QuoteRequest") : null
List resultsByKey = quoteRequest!=null && quoteRequest.containsKey("resultsByKey") ? quoteRequest.get("resultsByKey") : new ArrayList()
for (Map search : resultsByKey) {
Map searchInfo = (search.containsKey("searchInfo") ? search.get("searchInfo") : null);
String searchName = searchInfo!=null && searchInfo.containsKey("searchName") ? searchInfo.get("searchName").toString() : "";
List results = (searchName=="quotesMotor" && search.containsKey("results") ? search.get("results") : new ArrayList());
}
If I remove the semi-colons from the first or second lines in the For loop, I get an "unexpected token" error, but not if I remove it from the last line in the loop.
Is it due to Drools evaluating RHS lines as a single statement and so they must be separated inside any loops?
Note: I understand it is not best practice to code assuming semi-colons are not required, however I came across this issue while experimenting and am just interested to know the reason for the compiler error. Thanks.
I guess the answer is because of MVEL itself. Drools may be delegating the entire chunk of code to MVEL to evaluate and execute.
According to this guide, in MVEL the use of a semi-colon is not mandatory in cases where you have 1 statement, or in the last statement of a script.
Hope it helps,

Set local variable/fact in Drools rule engine

I have a simple rule that is based on TaskPlanning example. It looks like this:
rule "It is better if user does not overexceeds its hours"
when
$emp : Employee()
$task : Task( $taskType : taskType, employee == $emp)
accumulate( Task(employee == $emp);
$minutesOfEmplSpend : sum($taskType.getBaseDuration());
$emp.getMinutesAvailable() < $minutesOfEmplSpend
)
then
scoreHolder.addMediumConstraintMatch(kcontext,
$emp.getMinutesAvailable()-$minutesOfEmplSpend);
end
And OK, it is working. But I would also like to add additional constraint there. $task variable has isSerious property, that holds boolean value. I would like it to be also taken into consideration when adding medium constraint.
I would like to achieve something like this:
scoreHolder.addMediumConstraintMatch(kcontext,
$emp.getMinutesAvailable()-$minutesOfEmplSpend - ($task.isSerious == true ? 100 : 10) ));
But I am getting rules errors. I think I've tried everything - please at least point me to the right direction.
Normal java code should work, try $task.isSerious() instead of $task.isSerious

Lazy filter for one element

I'm refactoring some scala code to teach my coworkers about for-comprehensions, and I've got a line like:
for {
// ...
result <- components.collectFirst({ case section if section.startsWith(DESIRED_SUBSTRING) => section.substring(section.indexOf(DELIM) + 1).trim() == "true" })
} yield result
That's a bit long.
At first, I wished I could just skip the result <- ... followed by the immediate yield, as I can in Haskell, but then I noticed the processing going on inside collectFirst.
So I thought it'd be much easier to read as I should better do this as
for {
// ...
section <- components.filter(_.startsWith(DESIRED_SUBSTRING)).headOption
} yield section.substring(section.indexOf(DELIM) + 1).trim() == "true"
Which works, but it is less efficient, since filter has to process all the elements. I'd like to be able to use a lazy filter:
components.withFilter(_.startsWith(DESIRED_SUBSTRING)).headOption
But FilterMonadic doesn't seem to support headOption, and I can't figure out a way to derive it from the operations it does support. I'm sure there's a way with flatMap and some bf, but I'm too unfamiliar with the scala ecosystem at the moment.
If I want to stick with standard library tricks, am I stuck with
for {
// ...
section <- components.collectFirst({ case section if section.startsWith(DESIRED_SUBSTRING) => section })
} yield section.substring(section.indexOf(DELIM) + 1).trim() == "true"
Or is there something better I can use?
If you use components.find(_.startsWith(DESIRED_SUBSTRING)) that will give you an Option with the first element that meets the condition. Then, you can just map over it with any subsequent processing you need.

Entity Framework: combining exact and wildcard searching conditional on search term

I'm creating a query to search the db using EF. TdsDb being the EF context.
string searchValue = "Widget";
TdsDb tdsDb = new TdsDb();
IQueryable<Counterparty> counterparties;
I can do exact match:
counterparties = tdsDb.Counterparties.Where(x => x.CounterpartyName == searchValue);
or wildcard match:
counterparties = tdsDb.Counterparties.Where(x => x.CounterpartyName.Contains(searchValue));
But I want to be able to do both i.e. (psudo code)
counterparties = tdsDb.Counterparties.Where(x =>
if (searchValue.EndsWith("%"))
{
if (searchValue.StartsWith("%"))
{x.CounterpartyName.Contains(searchValue)}
else
{x.CounterpartyName.StartsWith(searchValue)}
}
else
{x => x.CounterpartyName == searchValue}
);
Now clearly I can't put an if statement in the where clause like that. But I also can't duplicate the queries: shown here they are hugely dumbed down. The production query is far longer, so having multiple versions of the same long query that vary on only one clause seems very unhealthy and unmaintainable.
Any ideas?
You should be able to use the ternary operator:
bool startsWithWildCard = searchValue.StartsWith("%");
bool endsWithWildCard = searchValue.EndsWith("%");
counterparties = tdsDb.Counterparties.Where(x =>
endsWithWildCard
? (startsWithWildCard
? x.CounterpartyName.Contains(searchValue)
: (x.CounterpartyName.StartsWith(searchValue)))
: (x.CounterpartyName == searchValue));
Did you test btw if querying by a searchValue that has an % at the beginning or end works as you expect? It might be possible that % will be escaped as a character to query for because StartsWith and Contains will prepend/append % wildcards to the generated SQL search term anyway. In that case you need to cut off the % from the searchValue before you pass it into StartsWith or Contains.