(defrule is-bling?
"Is something considered bling?"
[Datom [[e a v]] (= a :cost) (< 1000.00 v) (= ?item e)]
[Datom [[e a v]] (= a :material) (= v :gold) (= ?item e)]
=>
(println "Yes! It's over $1000 and made of gold!"))
--
You received this message because you are subscribed to the Google Groups "Clara" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clara-rules...@googlegroups.com.
To post to this group, send email to clara...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clara-rules/0529a367-5e65-43b8-85d0-0794111fac10%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Regarding Alan's points: I had assumed in my earlier post the inserted items would be of a tuple structure that could be directly destructured as a clojure tuple (e.g., fixed-length vector or sequence). Not being deeply familiar with Datomic, it's not obvious to me how a Datom is efficiently expressed as a Clojure tuple, but I assume there is an efficient way to do so.I do think we can avoid the performance penalty of matching against all Datoms by using a :fact-type-fn that uses the attribute as the fact type, as discussed above. This actually seems intuitive to me, since the "type" of a datom does seem to be defined by its attribute.
--
You received this message because you are subscribed to the Google Groups "Clara" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clara-rules...@googlegroups.com.
To post to this group, send email to clara...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clara-rules/4271ae0c-1c83-41ce-b283-5bdee02a625a%40googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Clara" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clara-rules...@googlegroups.com.
To post to this group, send email to clara...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clara-rules/a0b06221-0501-4f1c-b567-b98c9b0ddca0%40googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to clara-rules+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clara-rules/a30b6387-9c98-437a-914d-67166fa8783d%40googlegroups.com.
On your point about duplicate facts, unfortunately my intuition is that if you have something like an order - customer - product relationship that using unique ids would distinguish them and obviate the need for allowing duplicates into working memory. For your example instead of having more than one [customer-id product-id] tuple you could use [order-id customer-id product-id] that uniquely identifies each order* and that it would be nonsensical to have more than one tuple (in working memory) with the same id value combination.Just thinking out loud here.Alan
--
You received this message because you are subscribed to the Google Groups "Clara" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clara-rules+unsubscribe@googlegroups.com.
To post to this group, send email to clara...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clara-rules/766d1fa2-6a14-47f1-9a65-da6a5338df3a%40googlegroups.com.
If duplicates are not allowed, this is going to end up being based on equality, which will be slow if linear - so it'll end up resulting to some sort of hashing. Basically you'll end up with something like a hash map/set as the way facts are stored in memory.
Hashing and equality checking are not free and can definitely add up to significant costs. This is true for many POJOs (which Clara supports), as well as Clojure records (still don't cache hash code as of v1.8 see http://dev.clojure.org/jira/browse/CLJ-1224 ).
As an example, Drools logical insertions (ie tracked by the truth maintenance system (TMS)) do automatically manage duplicate logical insertions by storing a map of fact to a count of how many times it has been supported (ie equal objects inserted).
So it looks like:
Fact1 -> 1
Fact2 -> 4
When a fact is removed that is a key in this memory map the number associated with that fact is decremented. If it reaches 0 the fact is removed entirely and the process recurses for any other logical insertions that were based on that fact (ie TMS does it work).
I've seen this be a critical hot spot in terms of performance when dealing with large sets of rules against large sets of facts.
I always really appreciated the lack of this duplicate removal feature in Clara since it allows the rule writer to decide what a duplicate object means and what even constitutes a duplicate.
It is not necessarily always easy to fabricate some ID to avoid facts being equals. If you can't add it to the object you have to create a wrapper or something. This may be expensive to perform (space perhaps) this sweeping generation of new ID'ed facts depending on the domain.
However, it could be argued that Clara could provide an alternative implementation option that did behavior similar to Drools. It'd probably be quite a bit to maintain since it would seem to be an alternative memory implementation at least.
I'm afraid the ship has sailed on the cardinality/identity semantics, at least for the default behavior, since there is too much relying on these semantics today. If your problem space demands different behavior, it's possible to write a clara.rules.engine.ISession implementation that wraps another session, and checks a set for whether a fact had already been inserted.
We have analogs of the Order example Will mentioned earlier, and the current behavior is also easier to reason about in the context of rules asserting (and automatically retracting) facts. For instance, we might have multiple rules that assert (->CustomerNeedsSupport customer-id)...but if one gets retracted by truth maintenance (because the rule that inserted it becomes false), we obviously don't want to retract the others. I think insertion of facts by users and rules should behave consistently, in line with following the "least surprising behavior" for the system.It's true in many cases there are unique identifiers that prevent collisions, but not in all...and if a user runs into that situation where all inserted facts are retracted due to equality, that users will have a very difficult problem to debug.I realize this probably isn't the most satisfying answer for some, but it does appear to be the right tradeoff for the several Clara users we have internally and would be disruptive to change, so I think we'll need to stay the course on this one.
(def INSPECTION (path [:session (parser ci/inspect identity)]))
(defn matches "Find matching rules, and the tuples that match them." [state] (select-one [INSPECTION :rule-matches (selected? [MAP-VALS seq])] state))
(defn activations "Find the names of matching rules and the data the matches them." [state] (select [ALL (collect-one [FIRST :name]) LAST ALL :matches ALL FIRST] (matches state)))