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 equivalentMATCH
traversal for the aboveGraphQL
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 validMATCH
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 inS
. - For each traverse
t
in the complement ofS
, we entirely discardt
along with all the vertices and directives within it, and we add a filter on the previous traverse to ensure that the edge corresponding tot
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.