I was hoping the recent conversation regarding maps this would come up, but so far it
hasn't.
How do I check for conditions on the element referenced in the map?
So given the following scenario:
SearchItem is the item being searched for by the user
Item has the attributes: UPC (String) and OnSale (Boolean)
StockRoom has an attribute of stock which is Stock = HashMap<String, Item> (key
value is UPC)
Now let's say I want to write a rule that says, "If the provided Item is in
Stock, and on Sale.. purchase it"
rule "deal finder"
when
SearchItem($upc : upc != null) // see if a UPC was provided
StockRoom($stock : stock) // get a handle to the stock
HashMap (this[$upc] != null) from $stock // look for the UPC in stock
Item (onSale == true) from $item // Where do I obtain the reference handle that is
$item?
then
// Buy stuff
End
What I'm trying to understand syntactically is how do I obtain a reference handle to
the "Item" found in the HashMap reference (IE: $item) so that I can check
additional attributes on that Item.
I haven't found any good examples of how to do this yet.
________________________________
From: rules-users-bounces(a)lists.jboss.org [mailto:rules-users-bounces@lists.jboss.org] On
Behalf Of Edson Tirelli
Sent: Friday, August 21, 2009 9:16 AM
To: Rules Users List
Subject: Re: [rules-users] Maps in Drools
2009/8/20 André Thieme <address.good.until.2009.dec.14(a)justmail.de>
Would there not be an addition to the syntax needed, for the default
rule language? For mvel it would not require a change I guess.
No, as I mentioned to you, the idea is for the DRL to remain the same, so that the rules
author does not have to worry about what the IT guys are doing with the domain model. So,
the rules author would write:
Customer( name == "bob" )
The IT guy would simply use a configuration to tell the engine: this object type uses a
map format, that one is a POJO, that other is an XML entity, etc.
For instance, if he wants to do that in DRL (he could also use API, or conf files), he
could do:
declare Customer
@format( map )
end
declare Order
@format( pojo )
end
So, we have a clear distinction between the technical aspects and the business aspects of
the application.
Your clojure macro would generate always the same DRL code "Customer( name ==
"bob" )", but you said yourself that clojure is 100% java compatible, so
imagine the enterprise had a domain model implemented as pojos already and as part of the
new application some new entities are modeled in clojure. The macro would generate always
the same code, but you would configure some entities in the domain as POJOs and other
entities as Maps.
Hmm, but the MVEL syntax can not magically eliminate the eval. Under the
hood the map accesses will still be inside an eval. Marc confirmed that
a few days ago.
MVEL only hides this from the user. This is what I will also do.
But under the hood it will become
$a:Map()
$b:Map()
eval( $a.get("type") == "Customer" )
eval( $b.get("type") == "DailyOrders" )
Here I think we have other misunderstanding. I will try to explain, but ideally you need
to learn a bit about the Rete algorithm to see the whole picture. There are 2 types of
eval(). Inline eval() and top level eval(). What you wrote above is a top level eval,
meaning it will become a node in the rete network. So your example above generates an
"execution plan" (making an analogy with SQL) that will get all Maps in the
working memory, join them in tuples size 2, and then test each tuple for the 2 evals. So,
you see why this will generate C(n,2) partial matches, while C(n,2) as we know is
n!/(n-2)!, what is really bad for growing "n".
Now, the same thing could be written using inline evals as:
$a:Map( eval( $a.get("type") == "Customer" ) )
$b:Map( eval( $b.get("type") == "DailyOrders" ) )
In this case, the inline eval() will generate an alpha constraint in the network, i.e.,
it will be applied BEFORE the joins. So, instead of doing all combinaions possible between
all maps as above, it will first find all Customer maps and all DailyOrders maps and only
after that will make a join between them. So you get Customers * DailyOrders partial
matches. The above evals are semantically equivalent as:
$a:Map( this[ "type" ] == "Customer" )
$b:Map( this[ "type" ] == "DailyOrders" )
But currently I am forced to produce this cross product, as there is
no direct support for Maps yet.
I hope that by the above you see that the problem of the cross products is not a problem
with Maps support, but rather a question of how to write better rules. The same way you
can write 2 completely different SQL queries that return the same result but one is fast
and the other is completely heavy and slow, you can also write good rules and really bad
rules.
[]s
Edson