clara

http://www.clara-rules.org/
jeremy 2018-08-08T21:22:48.000016Z

@mikerod Do you know if there is a way to go from Java -> Clojure when rules are keywords and not records/java beans?

enn 2018-08-08T21:28:03.000376Z

I have a Clara rulebase that, for comprehensibility reasons, I’d like to split into “phases.” So, phase 1 gets a bunch of facts, the rules fire, and new facts are generated. Somehow, this becomes the input to phase 2, which fires a new set of rules, generating new facts. Etc. I’m not sure what the best way is to pass the output of one phase into the next. Originally I was thinking I’d just take the session from phase 1 and use that as the starting point for phase 2. But unless I’m missing something, it’s not possible to load new rules into an extant session. So I guess what I need to do is to just grab all the “output” facts out of phase 1 and insert them into a new session for phase 2. Is there a simpler way to do this than by writing (and then executing) a query for each and every fact type?

2018-08-08T21:30:01.000124Z

@enn > So I guess what I need to do is to just grab all the “output” facts out of phase 1 and insert them into a new session for phase 2. Is there a simpler way to do this than by writing (and then executing) a query for each and every fact type? I think this is likely a smoother approach (there is an alternative I can mention in a min) As far as worrying about querying for too many types, maybe you can make a “parent” type for the output types you care about and just have a query on that parent type.

2018-08-08T21:30:16.000020Z

@jeremy642 I don’t think I understand the question. You want to use rules with “keyword” sort of type dispatch, but on underlying Java objects? Maybe show a dummy example or something.

jeremy 2018-08-08T21:31:25.000245Z

I have rules built on a keyword type dispatch. I wasn't sure if there might be a way to create them from Java.

2018-08-08T21:32:05.000364Z

Another possibility is to just use one session with all the rules. I’m not sure what about your logic makes it where you’d want some rules to be separate from others. Are you worried about them running too early or something, performance?, etc

jeremy 2018-08-08T21:32:57.000212Z

More a question on Java -> Clojure interop I guess than clara-rules. How I might go about creating the necessary type map for clara-rules from Java.

jeremy 2018-08-08T21:33:50.000066Z

2018-08-08T21:34:32.000043Z

I don’t understand your situation enough, but there is something called “activation groups” that can also be considered in some cases that may relate to yours https://github.com/cerner/clara-rules/blob/0.18.0/src/main/clojure/clara/rules.cljc#L328-L331

enn 2018-08-08T21:35:07.000284Z

No, they’re all in one session now and it works fine performance-wise. It’s more about making it easier for the programmer to understand the universe of rules and fact types in play at a given point in the code.

2018-08-08T21:35:42.000234Z

@jeremy642 you can provide a custom fact-type-fn (and ancestors-fn if relevant) http://www.clara-rules.org/docs/fact_type_customization/

2018-08-08T21:36:34.000138Z

This may be what you are looking for. e.g. the fact-type-fn could take an arbitrary (Java) object and map it to some keyword/alternative typing system you have within the rules

2018-08-08T21:38:53.000396Z

A likely incomplete example, but perhaps inspiration to think about.

enn 2018-08-08T21:39:11.000360Z

And making it easy to ensure that an intermediate fact type (used to derive some other final result) does not get inadvertently referenced outside of its intended scope

2018-08-08T21:39:25.000370Z

I’m not sure if you already have a custom fact-type-fn or not though. You might since I see you have a map with :weather-fact-type

2018-08-08T21:39:45.000053Z

Clara’s default is clojure.core/type, which is implemented as (or (get (meta x) :type) (class x))

jeremy 2018-08-08T21:40:06.000250Z

Yeah I was just thinking of a way to take Java Maps and Convert it to Keyword Key Map in the fact-type-fn?

2018-08-08T21:40:30.000218Z

depending on what is priority, you may flip the if above and do alternative things. I was just showing the idea of what could be done at least.

jeremy 2018-08-08T21:40:31.000290Z

Currently the custom fact-type-fn looks for :type or something like that. I'll have to grab the work laptop. This just came to me off the top of my head.

enn 2018-08-08T21:40:35.000089Z

Maybe my whole idea is antithetical to the idea that a rules engine hides some of the order-of-execution concerns of regular code? I’m not sure.

2018-08-08T21:41:03.000124Z

so for the fact-type-fn you just need to return the type (a keyword in your case I think)

jeremy 2018-08-08T21:41:08.000369Z

Yep

2018-08-08T21:41:30.000207Z

but if you want to also work with the Java data as clj maps, like this: (< (:temperature this) 0), you’d have to convert the facts themselves coming into the session

2018-08-08T21:41:40.000277Z

which is different than the fact-type-fn

jeremy 2018-08-08T21:42:05.000331Z

Yeah that's how the rules work with them currently.

2018-08-08T21:42:05.000410Z

the fact-type-fn doesn’t transform the facts that are used during constraint matching. It just gives a value that is used as the “fact type” partitioning of the network

jeremy 2018-08-08T21:42:13.000072Z

Hmm ok

2018-08-08T21:42:34.000062Z

I’ve wrote Clara rules a bunch with external Java type data

2018-08-08T21:43:00.000163Z

What I’ve done typically is to have some fairly basic rules to match those types and apply any sort of useful filtering if performance was a conern

2018-08-08T21:43:13.000421Z

but then just had the RHS insert a clj type to use in all the rest of the rules

2018-08-08T21:43:32.000048Z

so the rule was sort of a transformation/mapping from Java to CLJ data structures

jeremy 2018-08-08T21:44:07.000014Z

Ahh, might be a decent idea.

2018-08-08T21:45:05.000315Z

(defrule find-java-things
  [JavaThing (= x ?x)]
  =>
  (insert! {:fact-type :thing
            :x ?x}))

2018-08-08T21:45:19.000310Z

but if you need the JavaThing in the end, for the query consumer

2018-08-08T21:45:23.000353Z

you can attach it to the facts

2018-08-08T21:45:30.000340Z

either as a first-class field, or metadata

jeremy 2018-08-08T21:45:43.000189Z

I was thinking about keeping the rules in a seperate jar. And allowing Java applications and Clojure applications import and use the rules in that jar. The question was just how to define the facts when the rules were all in Clojure and no beans were provided that allowed Java to create them.

2018-08-08T21:45:51.000291Z

(defrule find-java-things
  [?j <- JavaThing (= x ?x)]
  =>
  (insert! (with-meta {:fact-type :thing
                       :x ?x}
             {:source ?j})))

2018-08-08T21:46:23.000263Z

If it’s a classpath issue, where you won’t know the types ahead of time you’ll have to be more tricky

2018-08-08T21:46:38.000311Z

and also, you are going to hit reflection stuff I’d think that way

2018-08-08T21:47:28.000093Z

or you write your core set of rules in a type-independent rule set/session

2018-08-08T21:48:19.000171Z

and you have to write a separate ruleset that does know about specific type mapping parts - or maybe you don’t need rules for that transformation layer at all.

2018-08-08T21:49:21.000105Z

Yeah, I understand your reasoning then

2018-08-08T21:49:30.000069Z

You can separate them to independent rulesets if that helps reasoning

jeremy 2018-08-08T21:49:47.000218Z

I thought about just writing a interface for Java to call and create facts, insert into engine. But the rule engine itself would most likely need to be run in clojure and not instantiated from Java so it's pretty self contained. It'd save me the hassle of dealing with java vs clojure types.

2018-08-08T21:49:52.000185Z

there would be a slight cost of taking facts from queries of one session and inserting again into another session, but that may not really be a concern

2018-08-08T21:50:09.000237Z

but yeah, order independence is a key idea

2018-08-08T21:50:26.000016Z

and I’d also sort of argue that rules should be able to somewhat function in aggregation with one another

2018-08-08T21:50:48.000294Z

where they can all share related information when relevant, but they are also fine when the information they need isn’t present etc

jeremy 2018-08-08T21:51:19.000047Z

Java doesn't really need much control over the engine. Just to insert facts and get response from the queries.

2018-08-08T21:51:45.000237Z

> And making it easy to ensure that an intermediate fact type (used to derive some other final result) does not get inadvertently referenced outside of its intended scope I think this is the most interesting concern though.

2018-08-08T21:52:20.000250Z

If everything gets lumped together, I can see how it could become problematic if you were wanting to have a better control on scope

2018-08-08T22:09:42.000289Z

yeah, hard to say without fully understanding the setup you have