eql.md 6.1 KB

EliasDB query language

EliasDB query language (EQL) is a query langugage to search nodes in a partition of the graph database. Its syntax is designed to follow natural language supporting complex graph queries while keeping simple queries simple. A simple EQL query has the following structure:

get <node kind> where <condition>

It reads: "Get all graph nodes of a certain node kind which match a certain condition". The condition is evaluated for each node from the specified kind. For example to get all Person nodes with the name John you could write:

get Person where name = John

The result of this query is a table listing all data store nodes which have a node attribute name with the value John.

Where clause

A where clause supports the following operators:

  • Standard boolean operators: and, or, not

  • Standard condition operators: =, !=, >, <, >=, <=, in, notin, contains, beginswith, endswith, containsnot

  • Standard arithmetic operators: +, -, *, /`

  • Integer operations: // (integer division), % (modulo)

  • Regular expression operator: like

Operators can be combined. Expressions can be segregated using parentheses. Each where condition should end in a boolean value. List operators such as in and notin operate on sequences of values which can be declared with square brackets e.g. [1,2,3].

  • Where clauses also support the following constants: true, false, null

To explicitly define if a value represents a literal or a name of a node or edge attribute it is possible to prefix it with either attr: for a node attribute name, eattr: for an edge attribute name or val: for a literal. In the majority of cases however the query interpreter will determine the right meaning. The precedence is: node attribute, edge attribute, literal value.

EQL supports nested object structures on node attributes. A node value of { l1 : { l2 : { l3 : 123 } } } can be queried as:

<attr name>.l1.l2.l3 = 123

If the actual attribute name contains a dot then the attr: prefix must be used.

Traversal blocks

For the majority of useful queries it will be necessary to traverse the graph. Relationships between nodes can be matched with traversal specifications. A traversal specification has the following form:

<source role>:<relationship kind>:<destination role>:<destination kind>

All components of a traversal specification are optional. A traversal of all relationships can be expressed with:

:::

Traversal expressions in a query are defined as block expressions:

get <node kind> where <condition>
 traverse <traversal spec> where <condition>
    traverse <traversal spec> where <condition>
        <Further traversals>
    end
end

Traversal expressions define which parts of the graph should be collected for the query. Reading from top to bottom each traversal expression defines a traversal step. Each traversal step will add several columns to the result if no explicit show clause is defined.

Show clause

To control which data will be displayed in the final result it is possible to define a show clause. A show clause explicitly states which columns should be displayed in the result table.

get <node kind> where <condition>
 traverse <traversal spec> where <condition>
    traverse <traversal spec> where <condition>
        <Further traversals>
    end
end
show <show clause for column 1>, <show clause for column 2>, ...

The data can be defined by traversal position, as attribute name or as node/edge kind with attribute name.

Examples:

1:n:key  - Display the key of the start nodes
2:e:name - Display the name of the relationship from the 1 traversal step
Person:name - Display the name of the first defined Person node from the query
name – Display the name of the first defined node which has a name attribute

With clause

Operation which need to be applied once all rows of the result have been fetched can be defined in the with clause. If a with clause is defined it is always the last clause in a query.

get <node kind> show <show clauses> with <with operation>, <with operation>, ...

The following operations are possible:

  • ordering - Order a column (e.g. ordering(ascending Person:name) )

         Available directives: `ascending, descending`
    
  • filtering - Filter a column (e.g. filtering(unique 2:e:name) )

          Available directives: `unique` (column will only have unique values),
                                `unique count` (column will show unique values
                                              and a count of how many values were  
                                              encountered),
                                `isnotnull` (column will only contain not null
                                           values)
    
  • nulltraversal – Only includes rows in the result where all traversals steps

              where executed (i.e. do not include partial traversals)
              Available directives: `true, false`
    

Functions

Functions can be used to construct result values. A function can be used inside a where clause and inside a show clause. All function start with an @ sign.

Functions for conditions:

@count(<traversal spec>, <condition>) - Counts how many nodes can be reached via a given spec from the traversal step of the condition. Can optionally have a condition string which limits the traversal.
@parseDate(<date string>, <opt. layout>) - Converts a given date string into an unix time integer. The optional second parameter is the parsing layout stated as reference time (Mon Jan 2 15:04:05 -0700 MST 2006) - e.g. '2006-01-02' interprets <year>-<month>-<day> strings. The default layout is RFC3339.

Functions for the show clause:

@count(<traversal step>, <traversal spec>, <condition>) - Counts how many nodes can be reached via a given spec from a given traversal step. Can optionally have a condition string which limits the traversal.
@objget(<traversal step>, <attribute name>, <path to value>) - Extracts a value from a nested object structure.