datalevin

pauldeschacht 2024-10-10T07:18:20.987819Z

Hello all, I struggle with a query. I have a schema with a many cardinality. I want to find some entities in that many relationship. The query below is a simplified example: There is a “P1” entity with 3 followers (:follows) and I want to find only 2 of those 3 followers. My understanding is I can differentiate using [?p1 :follows ?p2] and [?p1 :follows ?p3]But as soon as I add the clause [?p1 :follows ?p3], the result set is empty.

(def schema {:follows  {:db/valueType :db.type/ref
                          :db/cardinality :db.cardinality/many}
               :name {:db/valueType :db.type/string
                      :db/unique    :db.unique/identity}})
  (def conn (d/get-conn "~/tmp/datalevin/test" schema))
  (d/transact! conn
               [{:db/id 1 :name "P1", :follows [{:db/id 2} {:db/id 3} {:db/id 4}]}
                {:db/id 2 :name "P2" :follows [{:db/id 10}]}
                {:db/id 3 :name "P3"}
                {:db/id 4 :name "P4"}
                {:db/id 10 :name "P10"}])
  (d/q '[:find
         ?p1 ?p2 ?p3
         :where
         [?p1 :name "P1"]
         [?p1 :follows ?p2]
         [?p2 :name "P2"]
         [?p1 :follows ?p3]
         [?p3 :name "P3"]]
       (d/db conn))
Can someone explain what I’m missing ? Thank you

2024-10-10T09:11:55.900909Z

Your query says give me entities which satisfy all those requirement. But none of them can satisfy all those requirements simultaneously. I’d write it like this:

(d/q '[:find (pull ?f [:name])
       :where
       [?p1 :name "P1"]
       [?p1 :follows ?f]
       (or
         [?f :name "P2"]
         [?f :name "P3"])]
  (d/db conn))
or like this if you don’t want to use pull and want the person they follow in the result set:
(d/q '[:find ?p ?n
       :where
       [?p :name "P1"]
       [?p :follows ?f]
       (or
         [?f :name "P2"]
         [?f :name "P3"])
       [?f :name ?n]]
  (d/db conn))

pauldeschacht 2024-10-10T09:21:27.028279Z

Thank you. That works . I still need to figure out why the p1, p2 and p3 in my example are not considered different entities, each one satisfying the requirements.

2024-10-10T09:31:47.109759Z

Because each entity must satisfy both those requirement: Give me followers that have name P2.

[?p1 :follows ?p2]
[?p2 :name "P2"]
Who also have name P3.
[?p1 :follows ?p3]
[?p3 :name "P3"]
There are no followers that have name P2 and P3. So you get no results. ?p3 and ?p2 are not bound to specific entities, all entities must satisfy both those patterns. So what’s happening is:
[?p1 :follows ?p2]
[?p2 :name "P2"]
Matches on:
{:db/id 2 :name "P2" :follows [{:db/id 10}]}
But it does not satisfy:
[?p1 :follows ?p3]
[?p3 :name "P3"]
So gets discarded. The same happens with:
{:db/id 3 :name "P3"}
Hope that makes more sense.

pauldeschacht 2024-10-10T09:48:36.473429Z

Thanks for the extra explanation. I misunderstood that (somewhere in the matching/join process) ?p2 and ?p3 would be bound to different entities (selected from the list of followers) and would satisfy the condition. It becomes clear now

2024-10-10T09:54:01.530899Z

It can and it can’t the way I think about it is the result has to satisfy all your where clauses. So this would be an example where p1 and p2 are different entities. Say you want to find someone who is followed by someone who is also followed:

(d/q '[:find ?n
       :where
       [?p1 :follows ?p2]
       [?p2 :follows ?p3]
       [?p3 :name ?n]]
  (d/db conn))
=>
#{["P10"]}

pauldeschacht 2024-10-10T09:56:36.318219Z

The last example is easier to understand.

2024-10-10T10:17:38.181189Z

Really? The first query requires that ?p2 and ?p3 be unified even though the attribute is cardinality-multiple? The "I'd write it like this" does not accomplish the same thing. The OP query wanted two distinct followers. The "I'd write it like this" tolerates a single follower.

2024-10-10T10:22:26.607069Z

Good point about the single follower.

2024-10-10T10:29:27.412129Z

So you’re right the OPs query does work with cardinality many in vanilla datascript.

Huahai 2024-10-10T17:19:46.190569Z

OK, sounds like we should file this as a bug

🙏 1
Huahai 2024-11-07T06:24:54.344669Z

Fixed

🙌 1
🚀 2
Jeremy 2024-10-10T09:53:50.034409Z

Hi everyone, I'm getting this error while trying to use datalelvin as a kvs, any pointers on how to get it working? Thanks nixos, java 19.0, clj 1.11

2024-10-10T10:11:57.716139Z

What :jvm-opts are you passing? The issue might be related to needing to pass: “--add-opens=java.base/java.nio=ALL-UNNAMED” “--add-opens=java.base/sun.nio.ch=ALL-UNNAMED” or not, but worth checking.

Jeremy 2024-10-10T10:25:50.728059Z

It worked. thanks. I literally just stumbled across https://github.com/lmdbjava/lmdbjava/issues/182#issuecomment-917838805 right as I saw your comment 😂

🎉 1