How do I express a many-to-many relation in a TypeQL schema?

Given a set of Authors and a set of Publications, I want to model an N…N (many-to-many) relationship between Authors and Publications, such that one publication may have many authors, and one author may have many publications.

How would I do that in TypeQL?

In TypeQL, relations are first-class citizens. In this way it differs from languages such as SQL where relations are expressed via foreign keys and join tables.

TypeQL relations are many-to-many by default, which means that we need only write:

define
person sub entity, owns name;
publication sub entity, owns name;
name sub attribute, value string;
authorship sub relation, relates author, relates authored;

allowing us to insert entities

insert
$king isa person, has name "Stephen King";
$straub isa person, has name "Peter Straub";
$talisman isa publication, has name "The Talisman";

Now there are actually two options for the relation model: either we create a separate relation for each person-publication link, or we use one N-ary relation per publication. The first approach yields

(author: $king, authored: $talisman) isa authorship;
(author: $straub, authored: $talisman) isa authorship;

while the second approach gives

(author: $king, author: $straub, authored: $talisman) isa authorship;

In this particular instance I would actually adopt the second approach. This is because it feels quite “natural”; when you look at a book, you’ll see all of its authors listed on the cover, and there are other meaningful attributes we can attach to an authorship - for instance we could add

define
publication-date sub attribute, value datetime;
authorship owns publication-date;

allowing us to insert the relation

(author: $king, author: $straub, authored: $talisman) isa authorship, has publication-date "1984-11-08";

authorship is a N-N relation ,also called hyperedge or hyperrelation
how to query the entity of authorship,and the data of authorship?

Depends on exactly what you’re looking for - some examples of match queries over authorships:

Retrieve all (author, authored) pairs:

match
(author: $author, authored: $authored) isa authorship;

Retrieve all (author, authored) pairs including publication date:

match
$r (author: $author, authored: $authored) isa authorship, has publication-date $pubdate;

Retrieve all publications co-authored by King and Straub:

match
$king isa person, has name "Stephen King";
$straub isa person, has name "Peter Straub";
(author: $king, author: $straub, authored: $authored) isa authorship;

On a similar note, how do I define a rule that detects a many to many relationship?

Hi, could you please provide a specific example of the kind of data patttern you want to detect? If you want to detect relations that have more than one roleplayers for multiple roles, you could do something like:

rule label-many-to-many:
  when {
    $a isa thing;
    $b isa thing;
    not { $a is $b; };
    $c isa thing;
    $d isa thing;
    not { $c is $d; };
    my-relation relates $rol1;
    my-relation relates $rol2;
    not { $rol1 is $rol2; };
    $rel ($rol1: $a, $rol1: $b, $rol2: $c, $rol2: $d) isa my-relation;
  } then {
    $rel has is-many-to-many true;
  };

You’d also need to allow my-relation to own is-many-to-many for this to work, and in general it’s pretty difficult to know if this will work without a specific example to test it on, so you may need to tweak this rule significantly to meet your use case.

What I am trying to do is make a system that learns. I wrote about it in topic: