OrientDB

The best way to integrate the compiler with OrientDB is by compiling to MATCH, our name for the SQL dialect that OrientDB uses. All query directives are supported when compiling to MATCH. Additionally, since OrientDB is a graph database, generating a GraphQL schema from an OrientDB database requires minimal configuration.

Important

We currently support OrientDB version 2.2.28+.

End-to-End Example

See Getting Started for an end-to-end OrientDB example.

Performance Penalties

Compound optional Performance Penalty

When compiling to MATCH, including an optional statement in GraphQL has no performance issues on its own, but if you continue expanding vertex fields within an optional scope, there may be significant performance implications.

Going forward, we will refer to two different kinds of @optional directives.

  • A “simple” optional is a vertex with an @optional directive that does not expand any vertex fields within it. For example:

    {
        Animal {
            name @output(out_name: "name")
            in_Animal_ParentOf @optional {
                name @output(out_name: "parent_name")
            }
        }
    }
    

    OrientDB MATCH currently allows the last step in any traversal to be optional. Therefore, the equivalent MATCH traversal for the above GraphQL is as follows:

    SELECT
    Animal___1.name as `name`,
    Animal__in_Animal_ParentOf___1.name as `parent_name`
    FROM (
    MATCH {
        class: Animal,
        as: Animal___1
    }.in('Animal_ParentOf') {
        as: Animal__in_Animal_ParentOf___1
    }
    RETURN $matches
    )
    
  • A “compound” optional is a vertex with an @optional directive which does expand vertex fields within it. For example:

    {
        Animal {
            name @output(out_name: "name")
            in_Animal_ParentOf @optional {
                name @output(out_name: "parent_name")
                in_Animal_ParentOf {
                    name @output(out_name: "grandparent_name")
                }
            }
        }
    }
    

    Currently, this cannot represented by a simple MATCH query. Specifically, the following is NOT a valid MATCH statement, because the optional traversal follows another edge:

    -- NOT A VALID QUERY
    SELECT
    Animal___1.name as `name`,
    Animal__in_Animal_ParentOf___1.name as `parent_name`
    FROM (
    MATCH {
        class: Animal,
        as: Animal___1
    }.in('Animal_ParentOf') {
        optional: true,
        as: Animal__in_Animal_ParentOf___1
    }.in('Animal_ParentOf') {
        as: Animal__in_Animal_ParentOf__in_Animal_ParentOf___1
    }
    RETURN $matches
    )
    

Instead, we represent a compound optional by taking an union (UNIONALL) of two distinct MATCH queries. For instance, the GraphQL query above can be represented as follows:

SELECT EXPAND($final_match)
LET
    $match1 = (
        SELECT
            Animal___1.name AS `name`
        FROM (
            MATCH {
                class: Animal,
                as: Animal___1,
                where: (
                    (in_Animal_ParentOf IS null)
                    OR
                    (in_Animal_ParentOf.size() = 0)
                ),
            }
        )
    ),
    $match2 = (
        SELECT
            Animal___1.name AS `name`,
            Animal__in_Animal_ParentOf___1.name AS `parent_name`
        FROM (
            MATCH {
                class: Animal,
                as: Animal___1
            }.in('Animal_ParentOf') {
                as: Animal__in_Animal_ParentOf___1
            }.in('Animal_ParentOf') {
                as: Animal__in_Animal_ParentOf__in_Animal_ParentOf___1
            }
        )
    ),
    $final_match = UNIONALL($match1, $match2)

In the first case where the optional edge is not followed, we have to explicitly filter out all vertices where the edge could have been followed. This is to eliminate duplicates between the two MATCH selections.

Note

The previous example is not exactly how we implement compound optionals (we also have SELECT statements within $match1 and $match2), but it illustrates the the general idea.

Performance Analysis

If we have many compound optionals in the given GraphQL, the above procedure results in the union of a large number of MATCH queries. Specifically, for n compound optionals, we generate 2n different MATCH queries. For each of the 2n subsets S of the n optional edges:

  • We remove the @optional restriction for each traversal in S.
  • For each traverse t in the complement of S, we entirely discard t along with all the vertices and directives within it, and we add a filter on the previous traverse to ensure that the edge corresponding to t does not exist.

Therefore, we get a performance penalty that grows exponentially with the number of compound optional edges. This is important to keep in mind when writing queries with many optional directives.

If some of those compound optionals contain @optional vertex fields of their own, the performance penalty grows since we have to account for all possible subsets of @optional statements that can be satisfied simultaneously.