Don't forget to add that to the wiki :) That goes for anyone here, the
wiki is open to all, if you find something useful in an email please add
it to the wiki site.
Thanks
Mark
Edson Tirelli wrote:
Hi Geoffrey,
Thanks for the additional info.
Regarding the need or not of ShadowFacts, I will try to explain what
they are, what is the problem, and how they are used to solve the
problem as there are other users that also questioned about them.
Hopefully, it will make things clear.
As we know, the Rete algorithm is simply a "network data-structure",
composed by nodes and connections between nodes. Some nodes have 1
input (alpha nodes) and other nodes have 2 inputs (beta nodes, that
perform joins between the tuple coming from the left and the fact
coming from the right). Both node types usually contains constraints
that in if evaluate to true will allow the fact/tuple to be propagated
to the next node and in if they evaluate to false, will block the
propagation.
Now, lets imagine what happens inside a given node, for instance a
beta node, when a fact is asserted. Lets use the following example:
rule "r1"
when
Person( $likes : likes )
Cheese( type == $likes )
then
...
end
As you can see, there will be a beta node (a join in this case) that
will get all Person instances (comming from the left side) and try to
match with every Cheese instance comming from the right side. We
stated in our rule that each person will only match the Cheese
instance whose type is the one the person likes ( Person.getLikes() ==
Cheese.getType() ). So, join node will check this condition for each
pair of Person + Cheese. For each pair that evaluates to true, it will
propagate, otherwise it will not propagate.
So, imagine you assert a person object [ Person( name = "bob", likes
= "brie" ) ] and a cheese object [ Cheese ( type = "brie" ) ]. This
will obviously match and activate the rule.
Then, after that you decide to change the person object that now
likes "muzzarela" instead of "brie". It does not matter if this change
occurs inside the engine (RHS) or in your application code. Then you
call modifyObject( person ) to tell the engine that the person object
changed, and of course the rule activation must be canceled. So, your
"modifyObject" command will go through the network and reaches the
join node we were talking about. Now, the node must check 2 scenarios:
1. Is there any old match that is not valid anymore? If yes, it needs
to propagate a "retract" from that node down the network (that will
cause the activation to be canceled in the end).
2. Is there any new match that is now valid? If yes, it needs to
propagate the new match from that node down the network.
The scenario 2 above is easy and straight forward, but the scenario
1 is the one we are interested. There are basically 2 ways for the
node to know if there was an old match that is not valid anymore. He
must either:
a. Remember each old match for the Person object
Or
b. Remember the old value of the Person "likes" attribute
Case "a" above is easy as it just iterates over the matches and in
case one of them is not valid anymore, it propagates a retract. For
case "b" above, it just uses the old value of the attribute (that it
remembers) to recalculate all matches and checks if the match continue
valid with the new value.
Well, that was the theory.
Talking about the implementation now, JBRules 3.0 implements the
solution "a" above. In each node of the network, for each tuple and
each fact that reaches that node, it remembers each match. It means a
complicated data structure with references to objects everywhere.
Also, in theory, it is faster than method "b", but the drawback is
that this solution uses a LOT of memory to store this match
information. In practice, the garbage collector and the object
instantiation simply kills performance for the general case.
So, in JBRules 3.1 we implemented solution "b". Now, instead of
remembering the matches, JBRules remembers the values for the object's
attributes. In theory it is slower, but for the general case it ends
up being faster, as it uses a less memory and instantiates a LOT LESS
objects. So, how can JBRules remember old object attributes, even if
you change an attribute from outside the engine?
This is what shadow facts do: ShadowFacts are a shallow copy of your
object's attributes, that in JBRules 3.1 are implemented as dynamic
proxies with lazy attribute cache. So, once the engine reads an
attribute for the first time, it will cache the attribute in the proxy
and will only update this cache at safe points.
As stated above, this is better for the general case, but not for
ALL cases. If your rule base has a small number of rules, but you
assert a huge number of facts in working memory, it may happen that
method "a" is better. But again, if your rule base grows, method "a"
seriously hurts performance and increases memory consumption.
Another special case (and this is the one I was trying to explain)
is when you don't change bound/constrained attributes. In the above
example, if once a person is asserted you never change the "likes"
attribute value ( or the "type" attribute in case of the Cheese ), it
means a node will never have a problem calculating its matches even if
the value is not cached. Please, node that in the above example you
can change Person.name and Cheese.price as much as you want, as they
are not "bound" nor "constrained". For this specific case, ShadowFacts
are simply overhead and bring no advantage.
A real example of this use case is Telecom Usage Events "guiding".
When the mediation/rating software for a telecom company is doing the
guiding to identify what is the user, service plan, etc for a given
usage event, the rules will be constrained by attributes that will not
(can not) change. So, for cases like this, ShadowFacts may be disabled
as they are only overhead.
Finally, answering your question, if you change a bound/constrained
attribute for an object WHILE the object is IN the working memory,
then you need ShadowFacts.
But, if you have a pattern in your application that, lets say,
always retract objects from the working memory, changes its attributes
and assert the object again, :) then you don't need ShadowFacts... but
I think this use case is not a real use case... is it? :)
So, I think making shadow facts optional may be a good feature to
implement.
Hope the explanation helps.
[]s
Edson
Geoffrey De Smet wrote:
With kind regards,
Geoffrey De Smet
Edson Tirelli wrote:
Geoffrey,
My guess is that ShadowProxyFactory is failing to match a method
that is declared in a superclass or interface with the overriden
method in a subclass. Because of this, it is trying to proxy 2 times
the same method. I will take a look in it asap.
thanks Edson, though there is no real rush, but it's probably
something critical for the m1 release for most use cases ;)
Anyway, here's my class:
public class Match extends AbstractPersistable
implements Comparable<Match>, Solution {
// ...
// Implemented from Comparable<Match>
public int compareTo(Match lesson) {
// Overwritten from Object, implemented from Solution
public Match clone() {
// Overwritten from AbstractPersistable
public String toString() {
}
Regarding your question, what I mean is to use JBRules as a
"classification (discrimination) network". It means your rules will
simply match objects with the single intent of identifying or
grouping the objects and will not change bound/constrained fields in
the objects. This is a valid use case, but not that common I guess.
And when you don't change bound/constrained field values during the
fact lifecycle, you don't need shadow facts.
- I don't modify constraints field in the RHS of rules, but I do
modifty them outside the rule engine (in the same thread), just
before calling modified + fireAllRules
- I do assert some logical objects in the RHS of rules.
Do either or both of these violate a "classification (discrimination)
network"?
[]s
Edson
Geoffrey De Smet wrote:
http://jira.jboss.com/jira/browse/JBRULES-575
I can't seem to manage to isolate the problem :/
It's not just because I have 2 different references to Team in Match
- because I wrote an integration test with Cheese and CheeseCouple
that worked.
See the issue for more info.
I am using drools3 in a single-threaded context - would that
suffice to have no need of shadow facts? What does "using it as an
discrimination network only" mean in practice?
With kind regards,
Geoffrey De Smet
Edson Tirelli wrote:
Geoffrey,
Plz, if you can open a JIRA with a sample it would be great.
Probably some kind of unexpected method name conflict.
Regarding the feature, right now it is mandatory, but I was
talking to Mark to make it optional. Unfortunally Shadow Facts are
one of those necessary evils. If you ever change a fact attribute
in your network, that fact needs a shadow fact. So, unless you use
the engine simply as a discrimination network, you will need them,
but the idea is to make them optional and better yet on an object
type basis, in a way that users can turn it ON only for those
types where it is really needed.
[]s
Edson
Michael Neale wrote:
Geoffrey, yes that does sound like a bug. The automatic
proxy/scheduling is quite new, and will take some time to
stabilise - could you create a test case and JIRA, and email me
please (with the JIRA, so I make sure it is not lost) ? I will
then (with edson) take a look into it, as there will have to be
changes to the ASM code that generates the proxy no doubt. I am
not sure if proxy/shadowing will be optional or not - haven't
been tracking progress with that (in any case it should be
transparent to you) - Mark or Edson can fill in on the details
for that for 3.2.
Michael.
On 11/30/06, *Geoffrey De Smet* <[EMAIL PROTECTED]
<mailto:[EMAIL PROTECTED]>> wrote:
If it isn't a known bug, I 'll happily make another testcase
patch.
I am pretty sure it's because I have 2 different references
to Team in
Match, namely homeTeam and awayTeam.
With kind regards,
Geoffrey De Smet
Geoffrey De Smet wrote:
> I just tried the trunk (to compare a benchmark between it
and the
> branch), but I got an error, anything I can do about it?
> Are shadow facts optional? (or are they better always anyway?)
>
> java.lang.ClassFormatError: Repetitive field name/signature
in class
> file
net/sf/taseree/samples/travelingtournament/domain/MatchShadowProxy
>
>
> Here's my Match class:
>
> public class Match extends AbstractPersistable implements
> Comparable<Match>, Solution {
>
> private Team homeTeam;
> private Team awayTeam;
>
> private Day day;
>
> // getters, setters, clone(), toString()
>
> }
>
> AbstractPersistable has a Long id with getters/setters
>
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email