LEELA QUERY LANGUAGE

Leela Query Language or simply LQL is the gateway to insert data or query the database.

This document is divided into three sections. The first part describes the structure of the language. The second one is graph manipulation and querying [edges and vertexes] and the final part is property manipulation and querying.

LQL

The language is built on the idea of commands with subcommands and arguments. For instance, consider this example:

  make (foo::bar)

The sintax above is used to create a vertex with name foo::bar. There are commands that takes no arguments:

  stat

And there commands with subcommands like attr:

  attr get 1d1a751c-622a-11e5-a7b4-efda49744bfe
  ^    ^   ^
  ^    ^   target/object
  ^    subcommand
  command

The language has a few types as well:

  "lql"         : a string literal;
  (double 42.0) : a double value [64 bits float type]
  (int64 42)    : 64 bits signed integer;
  (int32 42)    : 32 bits signed integer;
  (uint64 42)   : 64 bits unsigned integer;
  (uint32 42)   : 32 bits unsigned integer;
  (bool true)   : boolean value;

Lastly, leela objects have namespaces. Namespaces completely isolates objects and properties, so that you can use the same identifier in two different namespaces without worries.

Every query must provide the namespace it is working on. Following is a complete example of what a lql query looks like:

  using (foo::bar) stat;
  ^     ^          ^   ^
  ^     ^          ^   query terminator
  ^     ^          command + arguments
  ^     ^
  ^     namespace to use
  ^
  command

Every command starts with a using command following by the namespace enclosed by parenthesis. The namespace is composed by two components, separated from ::. In the above case the first component is foo and the second is bar. More about this in the NAMING section.

NAMING

The identifiers in Leela are composed by two components. The idea behind this is that the first component serves as category or class for the name in question. Components are separated by ::. Now, consider the example:

  machine::warp0013

The first component is machine and the second is warp0013. Similarly:

  nic::00-01-02-03-04-05

This represents a network interface and its mac address.

GRAPH MANIPULATION

There are two commands that deal with the graph structure:

  • make : create vertex and edges;
  • path : navigate the graph;
  • kill : destroy vertex and edges;

MAKE

  QUERY: make (kind::name);
  REPLY: NAME

Creates a new vertex identified by NAME. Is replies with a NAME message. For example:

  > using (leela::sandbox) make (machine::warp0013);
  < user  | tree    | kind    | name     | guid
  < leela | sandbox | machine | warp0013 | cd8a5e22-622e-11e5-bb66-fb5334d472bc

The lines above need a little bit of explanation. The first line is the LQL query. In the examples we will use the > character to identify lines that are sent to the server. Following there is one or more response lines, identified by the < character. More information about the different types of answers at the final section of this document.

Let's now create an edge:

  QUERY: make GUID -[LABEL]> GUID;
  REPLY: DONE

This command requires vertex ids instead of names. Then, you can link two vertex with a given label which can be later used to navigate through the graph. Let's see an example:

  > using (leela::sandbox) make (machine::warp0013);
  < user  | tree    | kind    | name     | guid
  < leela | sandbox | machine | warp0013 | cd8a5e22-622e-11e5-bb66-fb5334d472bc

  > using (leela::sandbox) make (nic::01-02-03-04-05);
  < user  | tree    | kind | name           | guid
  < leela | sandbox | nic  | 01-02-03-04-05 | 1d8bd666-6230-11e5-a3d6-7b6f71a2eebc

  > using (leela::sandbox) make cd8a5e22-622e-11e5-bb66-fb5334d472bc -[nic]> 1d8bd666-6230-11e5-a3d6-7b6f71a2eebc;
  < ()

  > using (leela::sandbox) make cd8a5e22-622e-11e5-bb66-fb5334d472bc <[machine]- 1d8bd666-6230-11e5-a3d6-7b6f71a2eebc;
  < ()

The first two queries just register the vertexes, nothing new here. The last query is the one that creates the edge. Differently from vertexes, labels are just strings so there is no need to register them. Labels are enclosed by -[]>, the reason for this is that that string looks like an arrow. You can also change direction by using <[]- which creates an edge with the inverse direction.

The DONE reply is here represented by the () string because it has no payload.

PATH

The path command allows you to navigate through the graph. Creating edges and navigating through them are very similar. As a matter effect the syntax is almost the same:

QUERY: path GUID
QUERY: path GUID -[LABEL-GLOB]> ()...
REPLY: PATH

Path takes a variable number of arguments. It can be used with no arguments in which case returns all edges a vertex may have. Or you can provide some edges in which case the system will use information to navigate the structure. Examples:

  > using (leela::sandbox) path cd8a5e22-622e-11e5-bb66-fb5334d472bc;
  < label | guid
  < nic   | 1d8bd666-6230-11e5-a3d6-7b6f71a2eebc

  > using (leela::sandbox) path cd8a5e22-622e-11e5-bb66-fb5334d472bc -[n*]> ();
  < label | guid
  < nic   | 1d8bd666-6230-11e5-a3d6-7b6f71a2eebc

  > using (leela::sandbox) path cd8a5e22-622e-11e5-bb66-fb5334d472bc -[foo]> ();
  < ()

The first query retrieves all edges. The second one all edges that have a label starting with n. The last one attempts to retrieve edges with a foo label, which does not exists, thus an empty reply.

KILL

Kill commands are the dual of make commands. They share the same syntax:

  QUERY: kill GUID
  QUERY: kill GUID -[LABEL]> ()...
  REPLY: DONE

The second form destroy edges. The second form destroy vertexes and all information related [like properties and edges]. Sadly, deleting a vertex is not implemented.

PROPERTY MANIPULATION

Vertexes may have properties and you can change or retrieve them using the attr command. Properties comes in two flavors:

  • kv: key-value property;
  • ts: time-series property;

The difference between the two is that the former is indexed by time. You may think the kv property as a simple cell whereas the ts as an array in which the indexes are timestamps.

There are four operations you can do with kv properties, namely put, get, del and kls. The last one is used for enumerating the attributes. The same commands can be used for ts properties but the last one which is tls instead. Next we provide details about every one of them.

ATTR GET

You can use this command to retrieve both kv and ts properties.

  QUERY: attr get GUID "NAME" [WITH OPTIONS];
  REPLY: K-ATTR

This syntax is used to fetch kv properties. Similarly:

  QUERY: attr get GUID "NAME" [S:E]
  REPLY: T-ATTR

Fetches ts properties. The only difference is the last bit which contains the start and finish of the time-series. For example:

  > using (leela::sandbox) attr get cd8a5e22-622e-11e5-bb66-fb5334d472bc "foobar" [0:3600];
  < guid                                 | name   | series
  < 4eb3de70-cb80-11e3-b4dc-0f48fe0268e8 | foobar | (1443043943.0, 19.95), (1443044003.0, 20.25), (1443044063.0, 16.5), (1443044123.0, 16.2334), (1443044183.0, 19.9333)

FUNCTIONS

There are a few functions that can be applied to transform the data. map functions apply to each datapoint, which does not change the size of the series. reduce functions on the other hand are blocking and consume all data before yielding a value [but you can use window functions to control how much data]. Following a list of available functions:

  • map (+ N) : for each datapoint, datapoint + N;
  • map (* N) : for each datapoint, datapoint * N;
  • map (/ N) : for each datapoint, datapoint / N;
  • map (- N) : for each datapoint, datapoint - N;
  • map (N -) : for each datapoint, N - datapoint;
  • map max : for each datapoint yields the maximum found so far;
  • map min : for each datapoint yields the mimimum found so far;
  • map (ewma R) : for each point yields the exponential moving average using R as the alpha parameter;
  • map mean : for each point yields the current mean value;
  • map count : for each point yields the current size of the series;
  • map hmean : for each point yields the harmonic mean value;
  • map abs : absolute function [eg.: abs -9 = 9];
  • map ceil : ceiling function [eg.: ceil 2.1 = 3];
  • map floor : floor function [eg.: floor 2.9 = 2];
  • map round : rounding function [eg.: round 2.5 = 3];
  • map truncate : truncate function [ex.: truncate 2.3 = 2];
  • map sqrt : square root function;
  • map (log R) : logarithm base R;
  • reduce (+) : summation of the datapoints;
  • reduce (*) : product of the datapoints;
  • reduce min : the minimum value of the series;
  • reduce max : the maximum value of the series;
  • reduce count : the size of the series;
  • reduce mean : the mean value of the series;
  • reduce hmean : the harmonic mean value of the series;
  • reduce (ewma R) : the exponential moving average using R as the alpha parameter;
  • filter (> N) : yields datapoints with value > N;
  • filter (< N) : yields datapoints with value < N;
  • filter (>= N) : yields datapoints with value >= N;
  • filter (<= N) : yields datapoints with value <= N;
  • filter (N >) : yields datapoints with N > value;
  • filter (N <) : yields datapoints with N < value;
  • filter (N >=) : yields datapoints with N >= value;
  • filter (N <=) : yields datapoints with N <= value;
  • filter (N ==) : yields datapoints with values == N;
  • filter (== N) : yields datapoints with values == N;
  • window N max : groups N datapoints and yields the maximum;
  • window N min : groups N datapoints and yields the maximum;
  • window N (*) : groups N datapoints and yields the product of the series;
  • window N (+) : groups N datapoints and yields the summation of the series;
  • window N (ewma R) : groups N datapoints and yields the exponential moving average;
  • window N mean : groups N datapoints and yields the mean value;
  • window N hmean : groups N datapoints and yields the harmonic mean value;
  • time-window N max : groups N seconds of data and yields the maximum;
  • time-window N min : groups N seconds of data and yields the minimum;
  • time-window N (*) : groups N seconds of data and yields the product of the series;
  • time-window N (+) : groups N seconds of data and yields the summation of the series;
  • time-window N mean : groups N seconds of data and yields then mean value;
  • time-window N hmean : groups N seconds of data and yields then harmonic mean value;
  • time-window N (ewma R) : groups N seconds of data and yields the exponential moving average;

ATTR PUT

Use this command to insert/modify data. Kv properties looks like:

  QUERY: attr put GUID "NAME" VALUE [WITH OPTIONS];
  REPLY: ()

The value can be any value as described in the beginning of this document. Example:

  > using (leela::sandbox) attr put cd8a5e22-622e-11e5-bb66-fb5334d472bc "foo" "bar";
  < ()

Notice that put either inserts or updates the value. Now, for ts properties:

  QUERY: attr put GUID "NAME" [TIMESTAMP] VALUE;
  REPLY: ()

The syntax is the same but the [TIMESTAMP] bit. This should contain a timestamp, i.e, the number of seconds since Jan/01/1970. For instance:

  > using (leela::sandbox) attr put cd8a5e22-622e-11e5-bb66-fb5334d472bc "foo" [0] "bar";
  < ()

This inserts the value "bar" at the given timestamp.

OPTIONS

  • ttl:N sets an expiration time of N seconds for this data point. Example, an ttl of 60s:
  > using (leela::sandbox) attr put cd8a5e22-622e-11e5-bb66-fb5334d472bc "foo" [0] "bar" with ttl:60;
  < ()

ATTR DEL

Use this command to remove data. To remove kv properties:

  QUERY: attr del GUID "NAME";
  REPLY: ()

Similarly, to remove ts properties:

  QUERY: attr del GUID "NAME" [S:E]
  REPLY: ()

The only difference is the timestamp bit. This is an interval, and all the values from S to E [inclusive] will be removed.

Examples:

  > using (leela::sandbox) attr del cd8a5e22-622e-11e5-bb66-fb5334d472bc "foo";
  < ()
  > using (leela::sandbox) attr del cd8a5e22-622e-11e5-bb66-fb5334d472bc "foo" [0:3600];
  < ()

ATTR KLS/TLS

This allows you to enumerate properties by name using a glob-like syntax. The kls command is used to list kv properties. Unsurprisingly, tls is used to list ts properties.

  QUERY: attr kls GUID "NAME-GLOB"
  REPLY: NATTR

  QUERY: attr tls GUID "NAME-GLOB"
  REPLY: TATTR

A few examples:

  > using (leela::sandbox) attr kls cd8a5e22-622e-11e5-bb66-fb5334d472bc "*"
  < guid`                                 | names
  < cd8a5e22-622e-11e5-bb66-fb5334d472bc | cpu-idle | memory-free | swap-free ...

  > using (leela::sandbox) attr tls cd8a5e22-622e-11e5-bb66-fb5334d472bc "c*"
  < guid                                 | names
  < cd8a5e22-622e-11e5-bb66-fb5334d472bc | cpu-idle