Git Product home page Git Product logo

Comments (18)

iddan avatar iddan commented on August 17, 2024 2

I mean cardinality constraints: we use them for deciding how to display relations between entities (multiple = {cardinality != 1}). Currently we use OWL which has cardinality constraints but we are looking for alternatives

from typeql.

clembu avatar clembu commented on August 17, 2024 2

Shouldn't new defaults reflect the effective default behaviour in existing schemas? Prior to this, unless I misunderstood something, every edge between types is effectively (0,*) (unless @key or @unique, and excepting the player duplication case).
I posit the most sensible default to introduce would be @card(0,*), at least for the feature introduction, and maybe have a transition to a more common opinionated case later?

from typeql.

flyingsilverfin avatar flyingsilverfin commented on August 17, 2024 2

@clembu I agree that it would probably make sense if we were implementing just this feature. Having relations default to being guaranteed to be 'small' enables us to optimise relations heavily, which will benefit 90% of users' use cases significantly.

Additionally, we expect to break backwards compatibility with 3.0 as we optimise the storage layer and implement new features, so doing a single migration is favorable over doing two smaller ones in our experience. We are generally on hand to help our users migrate when they run into issues however.

Note that 3.0 is currently stalled behind implementing critical new features in 2.x, so the decision on the best default may still be revisited in the coming months.

from typeql.

haikalpribadi avatar haikalpribadi commented on August 17, 2024 1

You mean cardinality constraints or simply having more than 1 cardinality for each role, @iddan ? The latter is natively possible in Graql.

from typeql.

iddan avatar iddan commented on August 17, 2024

Cardinality is crucial for our model in K. We won't be able to use Graql without it

from typeql.

lveillard avatar lveillard commented on August 17, 2024

Cardinality and required are not the same thing. The combination of cardinality and required actually generate all these cases:

 Empty
 One  (cardinality one + required)
 AtMostOne (caridnality one)
 AtLeastOne (cardinality many + required)
 and Many (cardinality many)

I do like the interval terminology because it controls both!

Also could potentially enable to do something like this

has middle-name [$dynamic-value-matched-before, *]`

from typeql.

lveillard avatar lveillard commented on August 17, 2024

One limitation of the interval notation is not being able to define cases like Intervals.

Intervals can be undefined or have a cardinality of 2 but never 1!

Basic proposition:

For this use case we can use brackets (set) like this {0,2} which means cardinality can be either 0 or 2
For example for a date interval we would have either null or 02/01/2023, 05/01/2023 but always two dates.

Medium proposition:

For really complicated use cases, maybe enabling unions also: [0,7]U{10,11}

Hardcore proposition:

Same, but being able to define them dynamically using functions and matched data stored in the DB.

match 
$a isa metadata, has buyerCardinality $bc;

define
relates buyer, @cardinality([0, Max($bc)], [0,5]U{7,9})  //default as second param

Terrible example, but just to illustrate the crazy idea 😂

from typeql.

flyingsilverfin avatar flyingsilverfin commented on August 17, 2024

For TypeDB 3.0:

Problem to Solve

We wish to allow users to restrict cardinality on relations, role playing, and attribute owning.

Proposed Solution

Introduce the @card(min inclusive, max inclusive) to start with. Extended syntax will be:

  • @card(exactly) to shorthand @card(min = exactly, max = exactly)
  • @card(0, *) to allow an open range

This annotation will be valid on each connecting schema constraint:

define
reaction sub relation,
  relates input @card(0, *), # how many times in each reaction `input` can be played
  relates output @card(1, *), # how many times in each reaction `output` can be played
  relates catalyst @card(0, *);  # how many times in each reaction `catalyst` can be played

chemical sub entity,
  plays reaction:input @card(0, *), # how many times each chemical can play `input` in reaction relations (NOT per relation, can only be 0 or 1 per relation)
  plays reaction:output @card(0, *), # how many times each chemical can play `output` in reaction relations (...)
  owns name @card(0, 1); # how many names each chemical can play

This change makes sense with the requirement that no relation can have the same player playing the same role twice:
(input: $x, input: $x) - this allows the plays cardinality to have more meaning in restricting the number of connected relations.

We will also set a default on relates that assigned a @card(1) to every role, which the user should relax explicitly.

from typeql.

krishnangovindraj avatar krishnangovindraj commented on August 17, 2024

The broken symmetry asks the question:
Is there not a case to restrict the number of owners (of a given type) for a given attribute?

@unique is a case where the cardinality (1,1), but is that the only interesting cardinality for this case?

from typeql.

flyingsilverfin avatar flyingsilverfin commented on August 17, 2024

@krishnangovindraj we're not going to consider that for the first round, but you're correct to say it makes sense to introduce reverse-cardinality restrictions. Specifically, it makes sense for owns only.

@unique will actually be usable in with cardinality @card(0, *) - it just requires that every attribute is owned uniquely by the type, for each attribute that is owned.

from typeql.

flyingsilverfin avatar flyingsilverfin commented on August 17, 2024

Something further to think about is that we should allow modifying the behaviour of deleting a role player to 0 instances either throw an exception (cardinality violation) or auto-delete the relation. Related to vaticle/typedb#6787

from typeql.

james-whiteside avatar james-whiteside commented on August 17, 2024

I wonder if we should implement @card(1) as default for all edge-defining keywords, not just relates. I've tried a small example and found I had to stick in on nearly everything.

In general, there are three possible actions based on deleting a relation's roleplayer: throw an exception (restrict), delete the relation potentially recursively (cascade), and persist the relation (persist). I think it makes most sense to have restrict as the default behaviour. Specifically in the context of cardinality, persist isn't always possible so probably fallback to restrict should be the default in those cases. I've talked about this a bit in my IAM report.

from typeql.

krishnangovindraj avatar krishnangovindraj commented on August 17, 2024

I wonder if we should implement @card(1) as default for all edge-defining keywords

^ I would say this makes sense for attribute ownership, but not for plays as that would mean relations default to being one-to-one. I'd say many-to-many, many-to-one or one-to-many are more common.

from typeql.

lveillard avatar lveillard commented on August 17, 2024

Just a quick question: is @card(1) really the most common one? In most of my schemas 90% of relations edges and attributes edges are @card(0,1) or less commonly @card(0,*) but almost never card(1)

Look any sql or mongo schema out there, required attributes and references are fairly rare

from typeql.

james-whiteside avatar james-whiteside commented on August 17, 2024

Yeah I was just opening the discussion. The fact you've come back with a counter-example that quickly is probably a good sign that @card(1) default is a bad idea.

from typeql.

SullivanDaly avatar SullivanDaly commented on August 17, 2024

Implementing a way to chose default cardinality seems like an important feature.
The feature may have to be done on the schema for several reasons:

  • Being able to chose different default cardinality for different databases on the same server
  • Being able to keep this default value with export/import process.

One way to implement this default in the schema would be to:

  • Apply the wanted cardinality to the owns/plays/relates keywords between base/root type.
entity owns attribute @card(0, 1);
relation relates entity @card(1);
relation relates attribute @card(1);
relation owns attribute @card(0, 1);

Those cardinalities would be default ones and can be overwrite later in the schema for specifics purposes.

from typeql.

lveillard avatar lveillard commented on August 17, 2024

One additional proposition I would love to make related to cardinality management:

Imagine that we are adding a new edge or attribute to something that has already reached its limit. Since the user does not know this before performing the mutation, we have two options:

A) TypeDB cancels the full mutation stream (which might contain other mutations) and throws and error
B) TypeDB returns a "success" status but also provides a list of operations that did not succeed

I propose we choose option B for the following reasons:

  1. The mutation might have other inserts that the user expects to be committed
  2. The user already has the option to condition the mutation if desired (as the match group of statements acts like must-have conditions, it is possible to add these in the mutation). For instance, for Person owns name @card(0,1) we could do:
match 
not {$a has name;}; 
...
insert 
$a has name 'newOne'; 
$b ...
  1. In the future, with optionals (if optionals allow branches), users will also be able to fine-tune the expected particular outcome for their situation as needed.

For example, if they want all the inserts to be independent:

optional {
   match
      #@card (0,3)
      $a has tag $c;
      count($c)< 3;
   insert
      $a has tag 'last-tag';
};
insert
#other insertions in the same stream, unaffected by what happens in the optional branch

Or if they want it to block all the other inserts:

    match
      #@card (0,3)
      $a has tag $c;
      count($c)< 3;
   insert
      $a has tag 'last-tag';
      #...other inserts affected by the match clause that would be canceled

I hope this helps!

from typeql.

flyingsilverfin avatar flyingsilverfin commented on August 17, 2024

Absorbing this issue into the more refined and broader vaticle/typedb#7029 , please continue there.

from typeql.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.