@sashton,
Sorry for the delay. From my experience accumulators are relatively cheap with respect to memory/performance in scenarios where the state of the session that they are accumulating is relatively stable.
Performance can degrade in the event that there are massive amounts of logical retractions due to truth maintenance, but it would be directly linked to the data in the session and other rules that may feed into this rule.
To the second half,
> Not sure if using the accumulator and re-creating the set of ids — (set (map :id ?a))
— in the rule expression would cause any unexpected problems.
I believe that would require each B
in the session to generate the set again, perhaps using the distinct
accumulator instead might be ‘better’. Any updates to A
would also require this work to be redone.
Something like:
(defrule merge-things
[?ids <- (acc/distinct :id) :from [A (= ?name name)]]
[?total-quantity <- (acc/sum :quantity) :from [B (contains? ?ids id)]]
=>
(println ?name ?total-quantity))
In theory this would only have to recalculate the set when a new A
was seen and then only if that return value changed then re evaluation of the B
logic would have to occur.
Then again all of this needs to be taken with a grain of salt as data scenarios can change the behavior of performance while executing rules.insteresting error, I am using a private function inside the namespace of the rules and clara gave me the follow stacktrace
#error {
:cause var: #'secland.securities.contract-rules/now-in-inst is not public
:via
[{:type clojure.lang.ExceptionInfo
:message Failed compiling alpha node...
I would like to understand more why
@iagwanderson, Was the function was used inside the LHS of a rule?
nvm, i missed Failed compiling alpha node
. So the answer to my question would be yes.
The reason that this would occur would be due to how clara evaluates LHS/RHS. The LHS is assumed to be namespace agnostic, as nodes that make up the LHS(AlphaNodes, JoinNodes, ect.) could be shared across namespaces and rules in those namespaces, whereas the RHS(ProductionNodes) can’t be shared and can be seen as Namespace bound. This means that Clara evaluates LHS nodes outside of the original namespace that they are defined within, and production nodes are evaluated within the namespace that they are defined. So, by having a private function within the LHS of a rule clara will cause an exception to be thrown due to illegal access. I’m not sure if that is documented anywhere, but it probably should be… I will see if i can find any.
@ethanc thanks so much for the clear explanation, didn't find any explanation around it when I searched
I have a more general question about code organization
I have some rules that need to be run for specific clients and products, there is a recommended approach about how to organize the rules and the sessions for each situation?
I would like to enable some users to enable/disable a rule, so probably having a reference to it in a database
I guess it would depend on your use-case, i think the way i would handle them would be treating a namespace as a “feature package”. Then a given client could enable features(sets of rules) by namespace, of course through some abstraction(wouldn’t want consumers directly loading namespaces). That way when it comes to session creation you would only have to worry about loading a set of namespaces containing rules, ex
(defn load-session
[]
(let [client-namespaces (get-namespaces-by-client)]
<require namespaces if not already done>
(com/mk-session client-namespaces)))
per rule filtering would probably be more tricky.