Edson Tirelli schrieb:
> So, in principle having Maps support in the LHS is not a big challenge?
No. Just requires developing a set of classes to work with maps. Being
brief:
* Implement: MapObjectType extends ObjectType
* Implement: MapReadAccessor and MapWriteAccessor
* Add support to them into the builders (i.e., the actual wiring of the
new classes)
* Test everything... I probably forgot something, since there's been
quite some time since I worked on this.
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.
> Could you please explain this in a bit more detail?
Lets call |A| the number of A facts in the working memory and |B| the
number of B facts (i.e. cardinality). Lets call p(|A|,|B|) the number of
partial matches a rule will create given the cardinality of A and B.
Imagine your rule is:
when
A()
B()
then
This rule creates a join between A() and B() and the number of join
attempts will be: p(|A|,|B|) = |A| * |B|
Now, if instead of representing A and B as different classes you use
Maps with the type attribute as you was suggesting:
$a : Map()
$b : Map()
eval( ... )
The number of partial matches will be: p(|A|,|B|) = (|A|+|B|)! /
(|A|+|B|-2)!
Ah yes okay, I see what you mean.
Well, the current situation for me is that I have to do exactly that.
As it is typical for Clojure apps to store data in Maps I need support
for that. So, I want to allow rules like:
(map-rule "Rule name", "type"
(when
"Customer" ( $cust-id "id" )
"DailyOrders" (= 1 (get "count" $cust-id)))
(then
(println "match")))
This is semantically exactly the same as in your example, where Customer
and DailyOrders were POJOs, while they are for me Maps.
Draw the graph for these two functions and you will get the picture.
If
you have more than 2 patterns, situation gets worst and worst.
If instead of eval() you use some alpha constraints, things go down to
the same level as using different classes:
$a : Map( this["type"] == "A" )
$b : Map( this["type"] == "B" )
The above will result in the same p(|A|,|B|) = |A| * |B| partial matches.
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" )
And the only reason why I need to do it this way is because in its
current version Drools does not support Maps as 1st class objects.
If it would, then the eval would not be needed anymore.
So, for Clojure users (and basically everyone else who stores data
inside Maps, for whatever the reasons may be) it would be so good to
have that support.
You gave a perfect explanation of why this would be a great addition.
The actual rule syntax is not important for me. My lib will hide it,
as MVEL already does now.
But my lib will compile the rules into the fast native rule language.
It won't be interpreted or any slower than hand written rules.
But currently I am forced to produce this cross product, as there is
no direct support for Maps yet.
2009/8/19 André Thieme <address.good.until.2009.dec.14(a)justmail.de
<mailto:address.good.until.2009.dec.14@justmail.de>>
Edson Tirelli schrieb:
>
> I will skip the first half of your e-mail as I am not sure
what were
> the reasons for your nit-picking. If my explanation was not
helpful for
> the public it was intended to, you are welcome to explain yourself.
Oh, I did not intend it to sound like nit-picking. I only meant that
with a specialized syntax one can make rules operating on Maps looking
basically identical to the ones operating on POJOs.
> Regarding the part that matters, i.e., adding the support to
other
> fact types, Drools is prepared to support them in the LHS. Let me
> explain by example:
>
> when
> $c : Customer( name == "bob" )
> then
>
> For the reasoning algorithm, does not matter if Customer is a
POJO,
> an XML document, a Map with the "type" attribute set to
"Customer" as
> you mentioned, or whatever you can think. We use a set of interfaces
> that allows us to completely abstract that and we even supported 2
> different fact types as a proof of concept in the past.
That sounds good!
So, in principle having Maps support in the LHS is not a big challenge?
As I understand it, code inside an eval can not be cached and needs to
get executed every time and results in less performant code.
> The only reason we did not support multiple fact types yet for
Drools
> is the RHS. Our reasoning is that does not make sense to abstract the
> LHS if you don't do the same for the RHS. So, for instance, using
java
> dialect:
>
> when
> $c : Person( name == "bob" )
> then
> $c.setAge( 30 ) ;
> end
>
> If we will support that rule, written as is, for POJOs, and
we want
> to support Maps as facts, then our java parser needs to properly
handle
> the consequence code as $c.put("age", 30). Same thing if Person
was an
> XML document and so on.
From my perspective the RHS is not important at all for my lib and for
Clojure users who like to work with Drools.
For me mostly one thing is interesting: getting Map lookups out of eval,
so they can profit from exactly the same caching and optimizations that
exist for POJOs.
The RHS will be fully written in Clojure, and all challenges that occur
in it would have to be solved by myself.
If you Drools Devs could make it possible to give support for Maps in
the LHS, then most issues for Clojure users could be solved.
>
> If you want to contribute to the project solving this
problem, you
> are most welcome.
Unfortunately I have not enough Java knowledege and not time.
But I would like to contribute indirectly, by writing a lib for Clojure
users which will make Drools easily accessible to them. It would also
provide other users of Drools with an alternative syntax, which gets
compiled into the default rule language. (Not into mvel, as that seems
to be interpreted and runs a bit slower.)
> Regarding your rule rewrite, the way you propose is not feasible.
> Using multiple patterns of the same type without proper alpha
> constraints will lead to combinatorial explosion.
Could you please explain this in a bit more detail?
If Maps as 1st class rule objects, shouldn't my example then be exactly
the same as the one that you gave?
Your example was:
when
Customer( $custId : id )
DailyOrders( count[$custId] == 1 )
then ...
My example was:
rule "Rule name"
when
m1:clojure.lang.APersistentMap()
m2:clojure.lang.APersistentMap()
eval( m1.get("type") == "Customer" )
eval( m2.get("type") == "DailyOrders" &&
(m2.get("count")).get(m1.get("id")) == 1 )
then
((clojure.lang.IFn)globalVarWithClojureCode.get(17)).call())
end
And with direct Map support it could become something like:
rule "Rule name"
MapDefaultKey "type"
Salience 2
when
"Customer"( $custId : "id" )
"DailyOrders"( get("count", $custId) == 1 )
then
((clojure.lang.IFn)globalVarWithClojureCode.get(17)).call())
end
Instead of the one could have syntactical sugar which may look
unfamiliar: "count"[$custId]
If the key is not a string but a float one would even have
88.5[$custId] instead get(88, $custId).
This is just a matter of taste, and users could have their DSLs anyway.
André
--
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/
_______________________________________________
rules-users mailing list
rules-users(a)lists.jboss.org <mailto:rules-users@lists.jboss.org>
https://lists.jboss.org/mailman/listinfo/rules-users
--
Edson Tirelli
JBoss Drools Core Development
JBoss by Red Hat @
www.jboss.com <
http://www.jboss.com>
------------------------------------------------------------------------
_______________________________________________
rules-users mailing list
rules-users(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
André
--