oracle-samples/clara-rules

Provide a directed graph data structure of facts to their resulting facts

Closed this issue · 6 comments

Once #276 is complete we can explore creating a total graph data structure of inserted facts to the resulting facts via logical insertions. Until that enhancement is complete we don't have the information available to create such a graph data structure. I'm envisioning something like

(defrule cold-and-windy
     [ColdAndWindy]
     =>
     (insert! (->Cold)))

(defrule lousy-weather
     [Cold]
     =>
     (insert! (->LousyWeather)))

When a user inspected a session into which a ColdAndWindy fact was inserted, a graph data structure linking the ColdAndWindyFact to the Cold fact inserted as a result, and that Cold fact to the LousyWeather fact, would be returned. We'd also want the edges of this graph to have information on the rule that created the edge i.e. performed the insertion as well. If there is an accumulator condition in the rule each fact that matched the accumulator would link to the facts ultimately inserted. So, for example, in the following rule

(defrule record-cold
     (?min-temp <- (acc/min :temperature) :from [Temperature (< temperature 0)])
     =>
     (insert! (->RecordCold ?min-temp)))

every Temperature fact with a temperature value below 0 would link to the RecordCold fact inserted in this graph.

This is sort of similar to the goals of clara-tools, and it is possible that there is code there that is reused, but I'd like this data structure to be accessible outside the scope of that web application for users to utilize in domain-specific support tooling. The graph could be manipulated to show particular views, for example. Furthermore, the idea of a graph data structure and of visualizing one is in no way specific to Clara and ideally we'd leverage whatever general code for this exists. A very cursory examination of existing libraries suggests that https://github.com/aysylu/loom has gotten some traction in the Clojure community but I haven't looked into this deeply.

Good idea. The intent of the inspect namespace was to support exactly this type of functionality, although I started with a model centered around explaining rule activations as opposed to explaining the presence of facts. Just two different ways to approach the problem, but it's not surprising a fact-based explanation graph could be really useful.

I'm guessing such a fact graph could be produced as a transformation of existing explain functionality, plus #276 as you mentioned. As for the graph representation itself, we probably don't want to add any compile-time dependencies for this if we can avoid it, but using a graph structure that is easily adopted to loom or others makes sense. Also, a structure that can be inspected by hand with a simple pprint is really helpful. I experimented with some options here when working on the beta graph structure (with the schema defined at https://github.com/cerner/clara-rules/blob/master/src/main/clojure/clara/rules/schema.clj#L142), and found a simple Clojure structure containing collections of nodes and edges to be pretty easy to work with. Such a structure could probably be usable by future versions of clojure-tools or other tooling.

I have a draft of this at WilliamParker@b6b576e

I'm particularly curious to hear thoughts on the data model I used. I added some comments on the node records and I think the tests provide sufficient examples to get the idea.

I have submitted a PR for this at #283

Some notes:

  • As @rbrush suggested, I went with a graph schema based on raw Clojure data structures. Some uses cases I have in mind are such that programmatic manipulation of the graph will be necessary i.e. the graph will be far too large to look at a printed version of the whole thing. For these use-cases it could be helpful to translate the structure into something for which operations are predefined. It makes sense to have the initial representation be something independent of any dependencies though.
  • I added some doc relative to the draft, but I also think that the most illuminating doc is likely to be a page in clara-site with a visual representation of a graph generated by this functionality. Thoughts on how to best illuminate this functionality welcome.

One more thing - I debated whether to specify what condition each fact met in the graph. The argument for doing so is that it provides more information; the argument against is that in practice most of the time it is pretty easy to tell what condition a fact can meet on a rule based on its fact type and that explicitly saying this in the graph is just unnecessary verbosity. Similarly, I decided to just put the rule name in the graph, not the complete rule structure. If others have different thoughts we can revisit these tradeoffs.

If others have different thoughts we can revisit these tradeoffs.

The one thing I was thinking is that calling it :rule-name may be clearer than the field being called :rule.

#283 implemented this functionality. Closing.