Fork me on GitHub
#clara
<
2023-01-26
>
simonkatz17:01:18

(Please let me know if this is not clear enough — I can add more detail and some example code if necessary.) If I have a rule LHS that somehow finds a fact by running some Clojure code (outside of Clara fact matching), is it possible to add that found fact as a dependency for any facts that the RHS inserts? At the moment I am getting the LHS to search all facts of the relevant type and match on an ID, but that’s inefficient.

ethanc17:01:17

A little more information would probably be required for a proper answer, but my gut says that LHS bindings “should” possibly handle that.

simonkatz18:01:31

Thanks. I’ll try to get an example together — perhaps at the weekend.

simonkatz19:01:30

Here’s an example:

(ns clara-example
  (:require
   [clara.rules :as c]))

(c/defrule create-derived-thing
  [:thing-1 [{thing-1-key :key
              :as thing-1}]
   (= ?thing-1-key thing-1-key)
   (= ?thing-2
      (find-thing-2 thing-1))]
  [:test (some? ?thing-2)]
  [:thing-2 [{thing-2-key :key}]
   (= thing-2-key (:key ?thing-2))]
  =>
  (c/insert! {:type        :derived-thing
              :thing-1-key ?thing-1-key
              :thing-2-key (:key ?thing-2)}))

simonkatz19:01:35

The rule finds a fact of type :thing-1. It then calls find-thing-2, which returns a fact of type :thing-2.

simonkatz19:01:47

I want to insert a derived fact that depends on both the fact of type :thing-1 and the fact of type :thing-2. I’m telling Clara about the second dependency by looking at all facts of type :thing-2 and matching on the key.

simonkatz19:01:48

This is not very efficient!

ethanc23:01:20

Thank you, that's not at all what I was envisioning. Would the end goal be that thing-2 is visible via session inspection(http://www.clara-rules.org/docs/inspection/)? As a side note, i'd be interested in the performance characteristics of that join. Potentially re-writing it as something that would force a hashJoin node might help. ie.

(ns clara-example
  (:require
   [clara.rules :as c]))

(c/defrule create-derived-thing
  [:thing-1 [{thing-1-key :key
              :as thing-1}]
   (= ?thing-1-key thing-1-key)
   (= ?thing-2-key
      (:key (find-thing-2 thing-1)))]
  [:test (some? ?thing-2-key)]
  [:thing-2 [{thing-2-key :key}]
   (= thing-2-key ?thing-2-key)]
  =>
  (c/insert! {:type        :derived-thing
              :thing-1-key ?thing-1-key
              :thing-2-key ?thing-2-key}))
Then again, even the added performance of a HashJoin node might not be enough if you were dealing with extremely large numbers of thing-1 and thing-2.

simonkatz11:01:03

Thanks for your reply and suggestion. The end-goal is that Clara’s truth maintenance removes the derived fact if the supporting thing-2 is retracted. I’ve tried your suggestion in my real code, but it actually makes things slower. I think I need to check the HashJoin documentation carefully to understand the subtleties. FWIW, I’m dealing with a few thousand thing-2s and a few tens of thing-1s. And actually, a colleague has found a different approach that means I probably won’t pursue this. 🙂 (Something around having facts that wrap the data that contains the thing-1s and thing-2s.) Thanks again!

👍 2
ethanc15:01:47

Glad you found an alternative The doc on HashJoin: http://www.clara-rules.org/docs/hash_joins/ As a follow-up to the initial question, i do not believe there would be any mechanisms to inform clara that there existed additional facts that support the execution of a rule. So again, glad you found an alternative.

simonkatz15:01:57

Thank you, once more. I appreciate your help.