Skip to content

Releases: typedb/typeql

1.0.1

25 Apr 18:02
Compare
Choose a tag to compare

Distribution (for Java)

<repositories>
    <repository>
        <id>repo.grakn.ai</id>
        <url>https://repo.grakn.ai/repository/maven/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>io.graql</groupId>
        <artifactId>lang</artifactId>
        <version>1.0.1</version>
    </dependency>
</dependencies>

Changelog

  • We can now define type labels using UTF-8 character set (PR 59)
  • Restrict the grammars for type labels and ID values (PR 60)
  • Fixed a bug where adding an Aggregate object to a Set causes a NullPointerException to be thrown (PR 29, PR 30):
    GraqlGet.Aggregate query = Graql.match(var("x").isa("movie")).get().count("x");
    Set<GraqlGet> queries = new HashSet<>();
    queries.add(query); // no longer throws a NullPointerException
    
  • Renamed the following methods in Variable (PR 54):
    • asUserDefined() to asReturnedVar() to better reflect the functionality, which is to return the variables that have been added to the get clause.
    • isUserDefinedName() to isReturned() to better reflect the functionality, which is to check if a particular variable has been added to the get clause.

Graql 1.0.0

30 Mar 00:38
Compare
Choose a tag to compare

Independent, more elegant and strongly-typed

After 3 years of work, Graql now stands as an independent technology and gets its own GitHub repository! Given the amount of work that has gone into Graql, and the stage where it's at right now, we're proud to call it Graql 1.0.0.

Hit that star button, everyone! https://github.com/graknlabs/graql

Distribution (for Java)

<repositories>
    <repository>
        <id>repo.grakn.ai</id>
        <url>https://repo.grakn.ai/repository/maven/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>io.graql</groupId>
        <artifactId>lang</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

Architecture

Graql now stands on its own, independent from Grakn. However, Grakn uses Graql to enable the querying of the database. Think of Graql to Grakn as SQL to MySQL; Graql is the language, and Grakn is the database that implements Graql. This means, when we speak of "Graql", we could be referring to 2 different things:

  1. graql.lang: the "graql language"; the library that a user would use to build graql "query objects".
  2. grakn.core.graql: Grakn's "implementation" of the Graql language. This module/codebase contains the Graql algorithms and data structures (query engine, reasoner, analytics, etc.)l

Graql, the language, will now have its own product lifecycle, strictly as a language and independent from Grakn. Going forward, Graql becomes a dependency of Grakn.

Part of this architectural change also meant that we had to break the dependency from Graql language API to Grakn transaction API. You can no longer call query.execute(); instead, you pass a Graql query to a Grakn transaction: transaction.execute(query). Thus, importing Graql into your (Java) codebase becomes lighter, as it no longer brings in massive transitive dependencies. Your architecture (that relies on Graql) should be simpler, lighter and more reliable.

Most importantly, we can start centralising all Graql plugins in this repository, making it easier for us to maintain them with every change in Graql. So for those of you who have built Graql plugins for various environments, we would love to invite you to contribute to the new Graql repo!

API/Language

Graql's grammar has been significantly refined in this release. The higher level structure of the grammar has remained mostly the same, but the grammar definition has been refined to be more strongly-typed, elegant and easily understood.

You can find the full grammar definition in graknlabs/[email protected]:grammar/Graql.g4, in which we will review the changes below.

First of all, Graql parser method (Graql.parse()) expects a non-empty string, and the parse-list method (Graql.parseList()) expects at least one query/pattern. The order in which queries and patterns are written before parsing is now maintained in memory and string output of the queries/patterns.

eof_query           :   query       EOF ;
eof_query_list      :   query+      EOF ;
eof_pattern         :   pattern     EOF ;
eof_pattern_list    :   pattern+    EOF ;

As you can see at the top of the grammar file, Graql queries are now clearly defined as:

query   :   query_define    |   query_undefine
        |   query_insert    |   query_delete
        |   query_get       |   query_get_aggregate
        |   query_get_group |   query_get_group_agg
        |   query_compute   ;

Define and Undefine Queries are defined to accept statement_types (statements that describe types in the schema). Statements that do not strictly describe types are no longer accepted at parse time.

query_define    :   DEFINE      statement_type+ ;
query_undefine  :   UNDEFINE    statement_type+ ;

Insert Queries are defined as a set of statement_instances (statements that describe data instances) that could follow a match clause (which accepts patterns). Statements that do not strictly describe instances are no longer accepted at parse time.

query_insert    :   MATCH    pattern+    INSERT  statement_instance+
                |                        INSERT  statement_instance+  ;

Delete and Get queries shares the same grammar, based on the match clause of a set of patterns, except that one results in concepts being deleted, the other results in concepts being retrieved.

query_delete    :   MATCH    pattern+    DELETE  variables   filters  ; 
query_get       :   MATCH    pattern+    GET     variables   filters  ;

As you can see above, both Delete and Get Queries can be followed by "filters" to sort, offset, and limit the query results. The new filters syntax are written after at the end of the query, and can only be optionally written once in the described order - a more strict definition of the syntax that maintains its full semantic expressivity. The variable provided in the sort filter will also be checked to be within the scope of the query.

filters    :   sort?       offset?     limit?  ;

sort       :   SORT        VAR_        ORDER_? ';' ;
offset     :   OFFSET      INTEGER_            ';' ;
limit      :   LIMIT       INTEGER_            ';' ;

Group and Aggregate Queries now behave as functions applied to the results of a Get Query. group and aggregate are now independent from each other, and each function simply follows a Get Query with its function name and optionally followed by a variable, e.g. max $x, or group $x; min $y;.

query_get_aggregate :   query_get   function_aggregate  ;
query_get_group     :   query_get   function_group      ;
query_get_group_agg :   query_get   function_group      function_aggregate ;

With the new grammar, we are now able to filter the answer set in the Get Query, prior to applying an aggregate or group function. The variables provided in aggregate/group must be within the scope of the get query, but given that get ...; can take multiple variables and returns a unique set of answers, group and aggregate queries are now much more expressive than before. For example:

match $x isa person, has age $y, has email $z; get $x, $y; sum $y;
match $x isa person, has email $y, has email-provider $z; get $y, $z; group $z; count;

A pattern, which is provided in a match clause could either be a conjunction, disjunction, negation, or statement describing types or instances.

patterns            :   pattern+ ;
pattern             :   pattern_statement
                    |   pattern_conjunction
                    |   pattern_disjunction
                    |   pattern_negation
                    ;
pattern_statement   :   statement_type
                    |   statement_instance  ;

A conjunction or disjunction pattern is strictly determined by the curly brackets ({ and }) that wrap a set of patterns and the or keyword operator. Any set of patterns wrapped in{ and } are conjunctions, and any set of conjunctions separated by the or keyword form a disjunction. Notice that a semicolon ; terminates each pattern.

pattern_conjunction :   '{' patterns '}' ';' ;
pattern_disjunction :   '{' patterns '}'  ( OR '{' patterns '}' )+  ';' ;

We have also introduced negation patterns using the not keyword. Positive (non-negated) patterns are interpreted as the existence an instance of that pattern, negative (negated) patterns are interpreted as the absence of an instance of that pattern. Negation patterns in rules are allowed, as long as there is no recursion taking place within negated patterns. For more information, see: https://dev.grakn.ai/docs/pattern/negation.

pattern_negation    :   NOT '{' patterns '}' ';' ;

Type statements, which could be provided in a Define Query or a match clause, are now defined more strictly as type (which could either be a label or variable in a match clause, but only label in a Define Query), followed by one or more type_properties, strictly delimited by a comma (,).

statement_type    :   type    type_property ( ',' type_property )* ';' ;

You can find the full definition of type_property L101:L112. The following is an example of a type statement which you will write in a schema definition:

person sub entity, has key username, has name, plays employee;

We've also introduced a variation of the sub keyword: sub!. sub! allows you to query for the "direct" supertype of a given type. E.g.: If a sportscar sub car, car sub vehicle, then match sportscar sub! $x; get $x; will only return car, instead of all supertypes of sportscar which are {car, vehicle}.

Instance statements, which could be provided in an insert query or a match clause, are now defined more strictly as a statement that either describes a thing (entity, relation, or attribute), relation, or attribute. Each of the instance statements can be followed by one or more attributes, strictly delimited by a comma (,).

statement_instance  :   statement_thing
                    |   statement_relation
                    |   statement_attribute
                    ;

A statement_thing needs to always begin with a variable (full definition: L120:L124). For example:

$x isa some-thing, has some-attribute;

A statement_relation may or may not start with a variable, but needs to have role-players declared before the concept type and attributes (full definition: L125:L128). For example:

$x (role1: $y, role2: $z) isa some-relation;
(role1: $y, role2: $z) isa some-relatio...
Read more