clara

http://www.clara-rules.org/
Konstantinos Tzanidakis 2020-01-10T09:30:41.093700Z

Hi all, I'm back 🙂 . Sorry for the several questions and thank you very much for all your prompt and very helpful responses; it's been very enjoyable working with Clara. I am progressing very well in building up the ruling system in Clara however I am getting some OOMs when I surpass a certain number of facts in my application. My application has around 15 rules, some of which are fired by others, and the facts may well range between 300k - 2m, but when I go closer to the upper end I get OOMs. So, I thought that it may be reasonable to run a few benchmark tests (and maybe start profiling?). I tried the clara-benchmark repository and experimented a bit with the AccumInsert test; in this I've played with the number of Customers, setting it from 250k to 10m. I noticed that on my machine, Clara threw an OOM above 5m facts. I was wondering whether you have a direction to suggest on methods to cut down such costs? In my application the first try was to chop the initial facts only to the absolutely necessary fields required (I am using clojure maps as extracted from a DB) but without luck. Thank you all in advance!

2020-01-10T13:49:16.096900Z

@konstantinos562 2m facts themself would be quite a memory burden in the jvm I think. If it’s just memory issues is the heap space you’re giving enough?

2020-01-10T13:50:40.099200Z

You can use a profiler to look more at the memory layout but Clara will certainly take more space than those 2m facts since it has working memory structure it uses on top of what they already take alone. And if you have rules inserting facts based on them.

2020-01-10T13:51:20.100800Z

The benchmark stuff would be more aimed at execution time. Which isn’t too useful if you’re running out of memory. If it’s slow it’s probably due to GC thrashing before OOM

2020-01-10T13:52:19.102400Z

Or at least that’d hide any other perf issues.

Konstantinos Tzanidakis 2020-01-10T13:52:45.102900Z

Hi @mikerod, yes that's true, the heap space is set to 4G. I have tried to trim down the facts' fields to the absolute necessary, and now I am considering of using a strategy to reduce the size of facts sent to Clara

2020-01-10T13:53:20.103700Z

@konstantinos562 it’d be good to know how much of the 4G you are using before running the rules

2020-01-10T13:53:34.104200Z

To gauge how much clara is adding relative to that.

Konstantinos Tzanidakis 2020-01-10T13:54:59.106800Z

Hmmm good question, I haven't noted this down, although I think it's relatively low as I start from a clean repl.

2020-01-10T13:55:35.107900Z

But the diagnosing the issue will also come down to what you’re rules are doing. If they match too many facts in ways where they are producing factors like n^2 or more rule activations and new fact insertions - I think that already is putting you at quite a lot of objects in memory

Konstantinos Tzanidakis 2020-01-10T13:55:36.108Z

but will note this with VisualVM

2020-01-10T13:55:57.108600Z

Visualvm can be good to get some info for this.

Konstantinos Tzanidakis 2020-01-10T13:56:22.109500Z

Yes, that is more close to what happening

2020-01-10T13:56:36.110400Z

Also you can try to just jump heap to like 6G then 8G to get a sense of how much memory it really needs. Of course this may not be acceptable in your production, but for testing

2020-01-10T13:57:13.111600Z

Also Clara shouldn’t hold references to facts that can never match any rules.

👍 1
Konstantinos Tzanidakis 2020-01-10T13:57:16.111800Z

I think I will try another pass on the rules in an effort to downsize the domain

2020-01-10T13:58:10.113800Z

So in some situations, if you actually can filter out a bunch of stuff early, you could do some sort of “stream of facts” in a sense. But your calling code would also have to not hold references past inserting them to Clara and firing rules.

Konstantinos Tzanidakis 2020-01-10T13:59:17.114Z

I see what you mean

Konstantinos Tzanidakis 2020-01-10T14:00:55.115700Z

I am currently retrieving all facts from the DB, which maybe streaming this in Clara without holding a head would make a difference... thanks for the suggestion

2020-01-10T14:01:55.116200Z

Yeah to not have them all in memory at once I think you’d have to be a bit careful.

2020-01-10T14:02:36.117700Z

Not sure something like insert-all would be careful enough within Clara. Would probably have to like near N number at a time, then fire rules. Then repeat the next batch

2020-01-10T14:03:01.118600Z

But if they are mostly matching or even “partial matching” rules they will be held in memory. So it can be brittle

2020-01-10T14:03:47.120200Z

A fact is held in memory if it can even “potentially” be used to satisfy a rule later. That’s the “partial match”

💯 1
Konstantinos Tzanidakis 2020-01-10T14:03:54.120400Z

(I was just checking insert-all's source, as this is what I am using to insert facts - but will need to check a bit more carefully on the DB side too)

2020-01-10T14:04:12.121Z

Which intuitively makes sense. Since it may be needed later when new facts come.

Konstantinos Tzanidakis 2020-01-10T14:04:35.121700Z

Makes sense yeah

2020-01-10T14:04:40.121800Z

But yeah my first thought would be the original stuff I said. Understand memory use a bit more.

Konstantinos Tzanidakis 2020-01-10T14:07:44.122200Z

Thanks a bunch @mikerod

bartuka 2020-01-10T14:10:37.122900Z

hi @mikerod, I am trying to run the tests from clara repository and I keep receiving this error:

clojure.lang.ExceptionInfo: failed compiling file:src/test/common/clara/test_common.cljc {:file #object[<http://java.io|java.io>.File 0x1085a882 "src/test/common/clara/test_common.cljc"]}

bartuka 2020-01-10T14:11:15.123700Z

there is any setup I need to do when adding a new test namespace?

bartuka 2020-01-10T14:11:27.124Z

Caused by: java.lang.RuntimeException: Unable to resolve symbol: test-rule in this context

2020-01-10T14:12:46.125300Z

@iagwanderson are you working with clj or cljs for this? And explain what you’re doing a bit more. You added new test ns? How are you trying to run them?

bartuka 2020-01-10T14:13:55.126500Z

I am working with clj, but as I see it should work with cljs as well. I created a file called test_blacklist.cljc inside the test/common/clara directory

bartuka 2020-01-10T14:14:14.127Z

and I tried to run using a simple lein test which runs fine if I remove my new namespace

bartuka 2020-01-10T14:20:41.127600Z

I tried to run the lein test again only with this new empty namespace and I got this error msg already

2020-01-10T16:30:15.128Z

@iagwanderson I’d have to see your changes I think at this point to help

bartuka 2020-01-10T17:17:13.128700Z

This repository has the changes and the test file: https://github.com/wandersoncferreira/clara-rules

bartuka 2020-01-10T17:18:58.129400Z

I changed the compiler.clj file

2020-01-10T17:56:51.130900Z

Thanks. I’ll take a look in a few.

bartuka 2020-01-10T21:51:49.132400Z

Ok, thanks. There is no clear relationship between my implementation and the error messages

2020-01-10T22:03:08.133100Z

@iagwanderson you need to use def-rules-test for cross platform “common” tests

2020-01-10T22:03:36.133400Z

That may be your issue

2020-01-10T22:03:50.133900Z

Look at another test ns in that dir to see it used.

2020-01-10T22:03:58.134400Z

It’s used in all the rule sort of tests there.

bartuka 2020-01-10T22:04:29.135800Z

Uhmm... Ok. I will make this change.

2020-01-13T13:08:18.145800Z

For some background, in Clojure Clara can create sessions on the fly using eval, while in ClojureScript sessions have to be defined at compilation time typically using a call to defsession at the top level. The dynamic session building in Clojure ultimately uses eval, which is why it doesn't work in ClojureScript. Defsession-test essentially makes the static session building in ClojureScript tests look more dynamic without needing to create tons of top-level defs etc.

bartuka 2020-01-13T23:33:38.147Z

interesting!! I noticed during my tests that in these cases I should uses only the names of the rules that I was filtering inside the mk-session I was thinking that is was going to create the name with my current namespace in it

2020-01-10T22:04:33.136Z

Can’t say it’s certainly the issue. But likely. I can’t remember without looking a bit more

2020-01-10T22:04:58.136800Z

There are differences in how you would set this up in clj vs cljs.

2020-01-10T22:05:10.137300Z

So the test helper makes that not an issue

2020-01-10T22:05:15.137500Z

For portable test

bartuka 2020-01-10T22:05:43.138700Z

I never did cljc before, so I was betting on something related to that

bartuka 2020-01-10T22:06:41.139400Z

I will make the test work and open a PR for discussions around the implementation

bartuka 2020-01-10T22:24:13.141600Z

@mikerod looks like the Compiling ["resources/public/js/simple.js"] failed. because in the cljs_deps.js does not have definitions for my new file added

bartuka 2020-01-10T22:34:52.142300Z

fixed, lein do clean, compile 😃

👍 1
2020-01-10T22:51:29.143300Z

Yeah. I have a long standing issue to improve the cljs setup and build stuff. But it is involved. So for now have to work with this stuff as it is.