Comments (18)
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.
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.
@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.
You mean cardinality constraints or simply having more than 1 cardinality for each role, @iddan ? The latter is natively possible in Graql.
from typeql.
Cardinality is crucial for our model in K. We won't be able to use Graql without it
from typeql.
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.
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.
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.
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.
@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.
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.
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.
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.
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.
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.
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.
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:
- The mutation might have other inserts that the user expects to be committed
- 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 ...
- 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.
Absorbing this issue into the more refined and broader vaticle/typedb#7029 , please continue there.
from typeql.
Related Issues (20)
- Allow nested negation and universal quantification in rules HOT 3
- Allow binding of ownerships to anonymous variables in query patterns
- Ignoring repeated constraints
- Support modifiers (at least the limit) in all type of queries HOT 3
- Using standard form for numeric literals throws an error when parsed HOT 5
- [Feature Request] More operators and basic functions HOT 1
- Make annotated constraints to apply to subtypes HOT 4
- Allow negations and disjunctions without an exterior binding
- Unary negation
- Factor out typedb-common and typedb-proc-macro crates
- Sanitize rust macros to avoid forcing user's environment
- Give relation and value constraints explicit keywords
- Add deployment tests for Cargo and Pip snapshots
- Introduce a syntax element to explicitly end a query string
- Plays-as overrides break schema export
- Fetch: add a way to project an item into a list of attributes by label HOT 1
- Introduce syntax for interface covariance HOT 2
- Composition of interface implementations as high-level abstractions (traits)
- Allow casting of type variables to value variables HOT 3
- Ability to define metadata for types without replicating the information across all type instances
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typeql.