Fork me on GitHub
#clara
<
2021-03-04
>
Heather01:03:04

Hi I have a question. I’m playing with Clara Rules so that I can understand rules engines better. I have 2 queries that look something like this:

(defquery query-1?
  "Returns what is set on Record 1"
  []
  [Record1 (= ?foo foo) (= ?bar bar)])

(defquery query-2?
  "Returns what is set on Record 2"
  []
  [Record2 (= ?baz baz) (= ?oof oof)])
And I want to make a query that returns the aggregate of both the queries. Something like this:
(defquery unified-query?
  "Returns what is set on both Record 1 and Record 2"
  []
  ;; [Record1 (= ?hmm hmm) (= ?huh huh)
  ;; [Record2 (= ?ooh ooh) (= ?aah aah)]]
  )

Heather01:03:41

I’m not sure how to set up that unified query to return both Records. Is that possible? Or do I need a third Record that represents the 2 records together?

Heather01:03:39

I couldn’t find examples of aggregating queries in any of the tutorials I saw, which made me wonder if it’s not something that happens often- it seems like it would be.

ethanc01:03:22

Would Record1 and Record2 have anything in common?

ethanc01:03:51

(r/defquery q1
  []
  [:and
   [Rec1 (= ?hmm hmm) (= ?huh huh)]
   [Rec2 (= ?ooh ooh) (= ?ahh ahh)]])
would be the way to query both records, however since the records don’t share anything in common you would end up with a cross product, ex.
(defn test
  []
  (-> (r/mk-session)
      (r/insert (->Rec1 :a 1) (->Rec1 :b 2) (->Rec2 :c 3) (->Rec2 :d 4))
      (r/fire-rules)
      (r/query q1)))
ends up producing:
({:?hmm :a, :?huh 1, :?ooh :c, :?ahh 3}
 {:?hmm :a, :?huh 1, :?ooh :d, :?ahh 4}
 {:?hmm :b, :?huh 2, :?ooh :c, :?ahh 3}
 {:?hmm :b, :?huh 2, :?ooh :d, :?ahh 4})

ethanc01:03:57

or perhaps the less explicit way:

(r/defquery q1
  []
  [Rec1 (= ?hmm hmm) (= ?huh huh)]
  [Rec2 (= ?ooh ooh) (= ?ahh ahh)])
they both behave the same way

ethanc01:03:11

I can’t speak for other’s usage of queries, but in our stack it usually ends up boiling down to a single record type that encompasses several pieces of smaller data.

ethanc01:03:48

It should also be noted, to my knowledge, anything that is possible in the lhs of a rule should also be possible in a query

👍 6
Heather16:03:18

Yeah, they have nothing in common and I just wanted to squish them together without a cross product. I was getting a cross product, but really wanted to just concat them.

ethanc16:03:50

hmm, not sure i am following you there, however perhaps an accumulator or two might be what you are looking for:

(r/defquery q2
  []
  [?rec-1s <- (acc/all) :from [Rec1]]
  [?rec-2s <- (acc/all) :from [Rec2]])
which nets:
({:?rec-1s [#test_queries.Rec1{:hmm :a, :huh 1} #test_queries.Rec1{:hmm :b, :huh 2}],
  :?rec-2s [#test_queries.Rec2{:ooh :c, :ahh 3} #test_queries.Rec2{:ooh :d, :ahh 4}]})
note that this doesn’t have the niceties of the field level binding because of accumulator grouping semantics(and me wanting to avoid that), but instead offers the full records

ethanc16:03:26

acc in this context is an alias for clara.rules.accumulators