TQL manual
Teneo Query Language
Inquire is the Teneo Platform's integrated suite of services for Natural Language Interaction (NLI) log data manipulation and exploration.
Querying in Teneo is carried out using the Teneo Query Language (TQL), a proprietary query language designed for retrieving information from the Teneo Engine log data, which is generated by a conversational AI application during its interactions with users.
In Teneo Studio, querying is carried out in the Log Data Source window; read more.
TQL syntax overview
A TQL query consists of a command, a selection, and, optionally, a set of constraints and/or transformers and meta-parameters.
The command is separated from the selection by a space, the selection is separated by a colon from the constraints, the constraints/transformers are separated from each other by commas, and finally the meta-parameters are included after a space, as in the pseudo-code example below:
tql
1<command> <selection> : [<constraint1>|<transformer1>],
2[<constraint2>|<transformer2>],… <meta-parameters>
3
Where:
- The command is the operation that the user wants to carry out.
- The selection indicates what is retrieved and computed by the query. The selection can hold more than one variable.
- The constraints (optional) can be used to filter undesired data off results, e.g. by specifying a date range, or a required variable value; or it can be used to indicate a particular relation among the items, e.g. by indicating that an event should happen before another event.
- The transformers (optional) can be used to generate new data from the source data, e.g. by manipulating date strings, obtaining top N items from ranking lists, or matching strings against Teneo Solution Language Objects.
- Finally, the meta-parameters (optional) are additional operators used to indicate how to organize the query results.
The next sections provide a complete description of TQL commands, constraints, transformers and meta-parameters, as well as the support commands for sub-queries and saving query results.
Query constructs
The structure of data (sessions containing transactions, transactions containing events, and the three of them containing properties) is reflected in the TQL syntax, which requires and explicit construct marker indicating the path to reach any property in the data.
The following notations are used:
- s to refer to the session
- s.<attribute_name> to refer to an attribute of the session, e.g.
s.beginTime
- t or s.t to refer to a transaction
- t1, t2, t3, etc. to refer to different transactions. The digit does NOT indicate the order of precedence.
- t.<attribute_name> to refer to a transaction attribute, e.g.
t.time
- e, t.e or s.t.e to refer to an event
- e1, e2, e3, etc. to refer to different events. The digit does NOT indicate the order of precedence.
- e.<attribute_name> to refer to an event attribute, e.g.
e.type
.
Querying events
Events’ properties are identified using the e. construct.
For example:
tql
1e.fname
2
refers to the fname property of an event.
A notation digit can be added to the construct to differentiate different events. In the example below, fname and userInput are properties of the same event:
tql
1e.fname, e.userInput
2
whereas in the next example, fname and userInput are properties of two events that may not be the same one (although they can be):
tql
1e1.fname, e2.userInput
2
Note that the digits here do not imply order or sequence, merely difference. To specify the precedence order of events, use Skip-constraints, or the index property.
Querying transactions
Transactions are queried using the t. construct, which has two uses: to access a property at the transaction level, and to constrain a set of events to occur on the same transaction.
The example below specifies that duration is a property of a transaction:
tql
1t.duration
2
The following example refers to two event properties that co-occur in different events within the same transaction:
tql
1t.e1.fname, t.e2.userInput
2
Notation digits can also be added to the t. construct – e.g. t1, t2 – to refer to distinct transactions. The following examples specifies that duration and time are properties of two distinct transactions:
tql
1t1.duration, t2.time
2
Similarly, it is possible to combine independent transactions and events in a single construct. The example below refers to two independent transactions (t1 and t2). Properties fname and userInput are obtained from two independent events (e1 and e2) that co-occur in the same transaction (t1), whereas answerText property is obtained from event e3 in transaction t2.
tql
1t1.e1.fname, t2.e2.userInput, t2.e3.answerText
2
Note thought that the above TQL selection is not allowed in Inquire because it requires additional constraints. See the section Computational Costs of TQL below for more information about this constraint.
When the t. construct is not present, a query will search for all events matching a constraint, regardless the transaction they belong to. For example:
tql
1e1.fname, t1.e2.userInput, t2.e3.answerText
2
does not constrain the event e1 to belong to the same transaction as e2, and so all the events in the data will be considered.
Querying sessions
Session level properties are accessed by means of the s. construct. The TQL query is automatically scoped to a single session at a time, so this is the only construct that can be used to refer to session properties. For example:
tql
1s.beginTime
2
Note that this means that it is not possible to use digits – such as s1, s2 – to refer to two different sessions.
Querying backstage
Query scope
Teneo Inquire considers all elements in a single Log Data Source (LDS). When a query is executed, Teneo Inquire looks into all the all sessions, transactions, and events, as well as user-generated data, such as augmenters, saved results and solutions that are available in the LDS.
As aforementioned, a TQL query is automatically scoped to work within individual sessions. This means that an individual query can operate across transactions and events within a single session at a time (querying elements intra session) but does not perform searches in elements that belong to two different sessions (querying inter-session).
Computational costs of TQL and good practices
As mentioned above, it is possible to combine properties from independent events and transactions by adding digits to their construct - e1, e2, t1, t2, etc. This TQL ability is very powerful but it also has computational implications given that all events and transactions will be taken in consideration for every distinct construct. For example, in the following construct
tql
1t1.e1.fname, t1.e2.userInput
2
e1 and e2 are explicitly constrained to belong to the same transaction. Such construct takes into consideration all events having the property fname in a transaction and computes the cross product with all events having the property userInput within the same transaction.
In contrast, the following example
tql
1e1.fname, e2.userInput
2
computes the cross product between all events having the property fname and those having the property userInput, regardless the transaction they belong to.
Therefore, the more distinct constructs are used, the more computationally demanding the query is. Hence, indicating which transaction an event should belong to is highly recommended.
In fact, Teneo Inquire includes a query validation mechanism that checks for potentially dangerous queries that may be highly demanding. If such a query is identified, Teneo Inquire rejects it and does not execute it, and Studio displays a warning message informing the user the query has not been carried out. The user will need to review the constructs in both the query selections and the constraints and step them up where possible.
A good practice would be to include the event type in the queries, this reduces the number of comparisons required to compute the results. For instance, when selecting the userInput variable in the query, the type=="request" constraint could be added:
tql
1la e.userInput: e.type == "request"
2
When selecting the answerText variable, the type=="response" constraint could be added:
tql
1la e.answerText: e.type == "response"
2
Similarly, when selecting properties from a path event, it can be constrained by means of the pathType:
tql
1lu t1.e.fname : t1.e.pathType=="raise-flow"
2
Working with variables
There are several types of variables logged in the log data: flow variables (fv), session variables (sv), log variables (lv), and annotations variables (annotation.variables). These and how they are logged by Teneo Engine are further described in the Data Model section. This section shows the difference among them and how to query them. Session and flow variables: Teneo Inquire logs the values of these variables according to their type: string, integer, etc. However, a variable can be assigned different types in different events. In order to enable Teneo Inquire to deal with varying types, variable names are prefixed according to the table below. Also, flow and session variables are prefixed in Inquire with fv: and sv: respectively. Hence, the full name of a variable in Inquire becomes fv:TYPE:VARIABLE_NAME in case of flow variables and sv:TYPE:VARIABLE_NAME in case of session variables.
Type | Prefix | Variables as declared in Studio | Variable name in Inquire/Log data | Query example |
---|---|---|---|---|
Binary | bin | myBinaryVar | bin:myBinaryVar | la e.fv:bin:myBinaryVar |
Boolean | b | myBoolVar | b:myBoolVar | la e.fv:b:myBoolVar |
Integer | n | myIntVar | n:myIntVar | la e.fv:n:myIntVar |
Date | d | myDateVar | d:myDateVar | la e.fv:d:myDateVar |
Double | f | myDoubleVar | f:myDoubleVar | la e.fv:f:myDoubleVar |
String | s | myStrVar | s:myStrVar | la e.fv:s:myStringVar |
Array | a | myArrayofDouble | a:f:myArrayofDouble | la e.fv:a:f:myArrayofDouble |
Everything else, including map and null | o | myMap, myObject | o:myMapo:myObject | la e.fv:o:myMap, e.fv:o:myObject |
As seen in the table, arrays are prefixed with two values: a: which indicates that the variable contains an array, and the TYPE: which indicates the type of the values in the array, e.g. a:f:myArrayofDouble
.
Log variables: These variables are logged at transaction level and they can only contain a String, regardless if their content represent an Object. Hence, they do not need to be prefixed and they can only be constrained by means of string operators. Example la t.lv:intVar : t.lv:intVar ~= ".*\d.* "
Annotation variables: These variables can only happen within an annotation. They are logged as a map where each property is a key-value pair of strings-object, i.e. the key is a string and the value is an arbitrary object. Hence, annotation variable names are also prefixed according to their type, the same way as flow and session variables are. Note that strings in JSON are stored with quotes. Hence, they should be considered when trying to match their content.
Examples:
(1) la e.annotation : e.annotation.variable.f:confidence > 0.5
(2) la e.annotation : e.annotation.variables.n:order == 0
(3) la e.annotation : e.annotation.variables.s:name ~= "NN.POS"
Working with annotations
Annotations are a special type of data in Teneo Inquire which are organized in a nested structure.
Map annotation {
Long sentence-index,
Map<String,String> variables,
Long[] word-indices,
String name,
String action
}
The String value in the attributes of the variables property represents a JSON object having nested structures such as numbers, strings, maps or arrays. They can be used the same way as session or flow variables. See the sections Data Model and Annotations for additional details.
It is possible to use log data to query some of the Annotation data, for instance:
Annotation properties
(1)
tql
1lu e.annotation.sentence-index, e.annotation.variables,
2e.annotation.word-indices, e.annotation.name,
3e.annotation.action
4
A specific property in the variables map
(2)
tql
1lu e.annotation.variables.f:confidence
2
Numeric conditions over annotation.sentence-index
(3)
tql
1la e.annotation : e.annotation.sentence-index == 0
2
(4)
tql
1la e.annotation : e.annotation.sentence-index == in {0,1}
2
String comparisons over annotation.name and annotation.action
(5)
tql
1lu e.annotation : e.annotation.action == "added",
2e.annotation.name == "VB.POS"
3
(6)
tql
1lu e.annotation : e.annotation.action == "added",
2e.annotation.name ~= ".*SENTENCE_WORDS.*"
3
Numeric comparisons on annotation variables properties having numbers
(7)
tql
1lu e.annotation.variables.f:confidence : e.annotation.variables.f:confidence > 0.8
2
(8)
tql
1lu e.annotation : e.annotation.variables.n:sentenceLength == 1
2
String comparisons on annotation variables properties having strings
(9)
tql
1lu e.annotation : e.annotation.variables.s:words ~= ".*[hH]ello.*"
2
(10)
tql
1lu e.annotation : e.annotation.variables.s:words == "hello"
2
Array comparisons over annotation word-indices properties. Note that word-indices is an array of numbers
(11)
tql
1 lu e.annotation : e.annotation.word-indices ~~ 1,
2 e.annotation.word-indices ~~ 2
3
Note the use of the contains operator, this query returns annotations having the values 1 and 2 in the word-indices array. The above query can also be written in a more compact way as: lu e.annotation : e.annotation.word-indices ~~ {1,2}
(12)
tql
1lu e.annotation : e.annotation.word-indices == in {{0},{2}}
2
Search for empty values
(13)
tql
1lu e.annotation : notexists e.annotation.variables.s:words
2
Returns annotations which have no words property in the variables
(14)
tql
1lu e.annotation : notexists e.annotation.word-indices
2
Return annotations having empty arrays in word-indices
(15)
tql
1lu e1.id, !e1.annotation.word-indices : notexists e1.annotation.word-indices
2
Returns empty arrays AND events without annotations
Array comparison over annotation array type variables
(16)
tql
1la e.annotation : e.annotation.variables.a:s:words == {"hi","hello"}
2
Returns annotations having exactly the array {"hi", "hello"} as value for the variable a:s:words
(17)
tql
1la e.annotation : e.annotation.variables.a:s:words ~~ {"hi","hello"}
2
Returns annotations having "hi" and "hello" within the values of the variable a:s:words
(18)
tql
1la e.annotation : e.annotation.variables.a:s:words ~~ in {{"hi"}, {"hello"}}
2
Returns annotations having "hi" or "hello" within the values of the variable a:s:words
(19)
tql
1la e.annotation : e.annotation.variables.a:s:words ~= {"H.*", "h.*"}
2
Returns annotations where the variable value is an array of size 2, the first element matches "H." and the second matches "h."
However, the current Teneo Inquire version still has some limitation when dealing with annotations. It does not allow certain constraints such as:
Use of ranges with set constrain and array
(20)
tql
1lu e.annotation : e.annotation.word-indices == in {0..2}
2
Working with dates
Teneo Inquire data includes some date properties, such as the session begin time, which are all logged in Z zone using the format: yyyy-MM-ddTHH:mm:ssZ, e.g.: 2018-12-12T09:07:26Z. Dates are however displayed in the frontend using the locale of the host.
Furthermore, users can assign Date values to variables in Teneo using the scripting functionalities, for example, assigning a Date value to a flow variable using the on-drop script. These dates can be stored using the user preferred date/time format. However, note that Teneo Inquire will identify and store as Date those that comply with the ISO-8601, else they will be stored as a String.
TQL reference guide
Main TQL commands
Teneo Query Language currently supports five basic commands, as displayed in the table below – both full and abbreviated forms are valid TQL syntax:
Command | Abbreviated form | Return value |
---|---|---|
listAll | la | list |
listUnique | lu | list |
countAll | ca | integer |
countUnique | cu | integer |
distribute | d | table |
Count All
The countAll function counts all values matching the query and returns an integer: example (1) below counts all user inputs, including duplicates; example (2) counts the total number of user inputs containing the string "hello".
(1)
tql
1ca t.e.userInput
2
(2)
tql
1ca t.e.userInput : t.e.userInput ~= ".*hello.* "
2
Count Unique
The countUnique function counts all unique values matching the query and returns an integer.
Example (1) below counts all unique user inputs, excluding duplicates, whereas Example (2) counts the number of dialogs, that is, of unique sessions.
(1)
tql
1cu t.e.userInput
2
(2)
tql
1cu s.id
2
Note: Uniqueness is determined by string comparison and is case sensitive.
Distribute
The distribute function counts the number of occurrences for all unique values matching the query and returns a 2-column table of un-ordered counts.
The example below counts the number of occurrences for each unique user input (including empty values).
(1)
tql
1d t.e.userInput
2
Example output:
t.e.userInput | count |
---|---|
Bonjour | 1 |
What time is it | 12 |
Hello | 102 |
Hi | 7 |
How are you | 4 |
Note: Uniqueness is determined by string comparison and is case sensitive.
List All
The listAll function retrieves all values matching the query and returns a list.
The example below lists all user inputs, including duplicates.
(1)
tql
1la t.e.userInput
2
Example output:
t.e.userInput |
---|
Hello |
What time is it |
Bonjour |
Hi |
hi |
Hello |
What time is it |
Hi |
List Unique
The listUnique function retrieves all unique values matching the query and returns a list.
Example (1) below lists all unique session ids, while example (2) lists all user inputs, excluding duplicates.
(1)
tql
1lu s.id
2
(2)
tql
1lu t.e.userInput
2
Example output:
t.e.userInput |
---|
What time is it |
Hi |
Hello |
Bonjour |
hi |
how are you |
Note: Uniqueness is determined by string comparison and is case sensitive.
Selection
The selection specifies what data does the TQL query return. Variable names in the selection are re-used as column headers in the output. Queries composed of a selection with no constraints retrieve all existing matching items in the data. In contrast, constraints in the TQL query are projected onto the selection, which may result in null or empty results if a constraint is not applicable to a variable in the selection, e.g. due to values belonging to different events.
Handling null results (! operator)
Due to the nature of the Teneo Platform and the large amount of data fields that exist in a solution, TQL results often come with lots of null and undefined values - for example, the query la e.userInput
returns empty rows for all events not having the e.userInput property, which are the majority of them. This behavior slows down queries by producing a lot of meaningless results.
In order to obtain more convenient query results and enhance the overall performance, Inquire adds, by default, exists-like constraints for every item in the selection, which filters fields with data and removes nulls and undefined results.
Therefore, the queries listed below return equivalent results:
(1)
tql
1la s.id, e.userInput
2
(2)
tql
1la s.id, e.userInput : exists e.userInput
2
(3)
tql
1la s.id, !e.userInput : exists e.userInput
2
Retrieving null results
Nonetheless, since certain use-cases may require seeing undefined and null results, a short-hand syntax has also been introduced that allows to not add exists
-like constraints. By using the exclusion operator !, query results also include null results.
Please note that if both exists and ! appear in the same query, exists prevails.
Aliases
TQL supports aliasing using the as notation. The example below:
(1)
tql
1lu t.e.userInput inputs
2
produces the result:
Inputs |
---|
What time is it |
Hi |
Hello |
Bonjour |
hi |
how are you |
Aliasing can also be used as a shorthand for referring to outputs from transformers (see Transformers section). In the Trend example below, aliasing is used to access and display multiple elements of the result as specified in the selection:
(2)
tql
1lu t.e.userInput, tau, direction, p, z :
2 trend(min-tau="0.0", max-p="0.05") t.e.userInput
3 (tau, direction, p, z)
4
Example output:
t.e.userInput | tau | direction | p | z |
---|---|---|---|---|
What time is it | 0.2019696471802132 | - | 0.01 | -2.719869088995218 |
Bonjour | 0.1543033499620919 | - | 0.05 | -2.077960316065855 |
hi | 0.1497410977398209 | - | 0.05 | -2.016521733740252 |
Note: Inquire supports unique names only. This means that if two variables are assigned the same alias, only the last assignment is kept. In the example below, the result will be a single column containing the transaction time values. The session-level value from s.beginTime is not displayed.
(3)
tql
1lu s.beginTime time, t.time time
2
This behavior also applies to the variable name count which is automatically created by the distribute command; that is, only one variable called count can exist in the same output and only the last assigned value will be kept.
Also, aliasing cannot be used as a shorthand in the constraints. The following query would be invalid:
(4)
tql
1lu s.beginTime time: time > 2019
2
Constraints
Constraints are used to specify conditions that sessions, transactions, and events properties must fulfil. They are separated from the selection by the colon symbol (:) and consist of multiple terms, separated by a comma. The relation between a property value and its condition is specified by means of one of eight operators below.
Core constraint operators
TQL supports the eight basic constraint operators listed in the table below. The table shows a brief explanation of their function, an indication of whether or not they support regular expressions, what field types they apply to, and example event properties they can be applied to.
Operator | Function | Applies to | Example |
---|---|---|---|
== | equals | strings, numeric, date, array | userInput, index, beginTime |
!= | not equals | strings, numeric, date, array | userInput, index, beginTime |
~= | Matches (regex) | Strings, array | userInput, folder, fname |
!~ | not matches (regex) | Strings, array | userInput, folder, fname |
~~ | contains | analyzed text, array | userInputWords, answerTextWords word-indices |
!~~ | not contains | analyzed text, array | userInputWords, answerTextWords word-indices |
exists | x exists | any | any |
notexists | x does not exist | any | any |
>, <, >=, <= | greater than x, less than x, greater or equal than x, less or equal than x | numeric, date, numeric array | transactionsCount, beginTime, |
The exists and notexists operators are special in that they only take one argument (the event property to check) and return a match if it exists.
The contains operator ~~ can be used to perform case-insensitive queries of userInputWords and answerTextWords, by checking if a field contains or does not contain a word or word sequence. This is possible because these two fields are stored as analyzed text, which is lowercased, tokenized, and normalized before being stored as an array of tokens (words).
Example
The example below, which retrieves a list of user inputs, consists of a constraint with three terms specifying that the user session must have been initiated in March 2015, one of its events must have raised a flow located in the "Safetynet" folder and the event that contains the userInput and the event indicating the folder name are related in the same transaction:
tql
1lu t.e1.userInput :
2s.beginTime == "2015-03",
3t.e2.folder ~= ".*?[S|s]afetynet.*?",
4t.e1-{pathType=="flow-trigger"}>t.e2
5
Using core constraint operators with array type attributes
The eight basic constraint operators listed above can be applied against array type attributes. In this case the constraint is specified by means of one of the constraints operators and the possible values enclosed by curly brackets {}.
These are examples on how to use the constraint operators with arrays:
(1)
tql
1la e.sv:a:s:words : e.sv:a:s:words == {"hello", "hi"}
2
Returns all cases where the value of the variable e.sv:a:s:words is exactly the array {"hello", "hi"}. Note that the equals operator does an exact match, that means: the size, the order and the value of each of the items of the array must match.
(2)
tql
1la e.sv:a:s:words : e.sv:a:s:words ~~ {"hello", "hi"}
2
Returns all cases where the value of the variable e.sv:a:s:words contains "hello" and "hi". In this case nor the size of the array or the order matters. It only needs to contain both: "hello" and "hi".
(3)
tql
1la e.sv:a:s:words : e.sv:a:s:words ~~ "hello"
2
Returns all cases where the value of the variable e.sv:a:s:words contains "hello". Note that in this case it is not needed to enclose the possible value in curly brackets. The use of the operators contains/not-contains against arrays specifying just one single possible value is the only exception where the curly brackets are not required.
The above is equivalent to the following query:
tql
1la e.sv:a:s:words : e.sv:a:s:words ~~ {"hello"}
2
(4)
tql
1la e.sv:a:s:words : e.sv:a:s:words ~= {"h.*", "b.*"}
2
Returns all cases where the first element of the variable value matches "h.*" and the second element matches "b.*". Note that the size of the array matters, in the above example only arrays of size two will match the constraint, as well as the order of the regex expressions in the constraint.
(5)
tql
1la e.sv:a:d:dates : e.sv:a:s:dates ~= {"2018.*", "2019.*"}
2
Returns all cases where the first element of the array matches "2018.*"and the second element of the array matches "2019.*". Note that in this case the regex operator is used against an array of dates. Inquire allows the usage of the regex operators against any type of array; if the elements are not strings, their string-value will be automatically calculated before applying the operator.
(6)
tql
1la e.sv:a:n:numbers : e.sv:a:n:numbers > {1, 2}
2
Returns all cases where the first element of the array is greater than 1 and the second element of the array is greater than 2.
Set-constraints
Set constraint allows a condition to be evaluated against more than one possible value grouping the result of them in an OR. Set constraint is specified by means of one of the constraints operators above, the reserved word in, and possible values enclosed by curly brackets {}.
The example below will return user inputs that consist of only lower case "hi" OR lower case "hello":
(1)
tql
1la t.e.userInput : t.e.userInput == in {"hi", "hello"}
2
Note: the previous TQL query would be expanded as:
(2)
tql
1t.e.userInput == "hi" OR t.e.userInput == "hello"
2
Set-constraints is currently the only way of constraining value ranges.
For example, the TQL query below will return user inputs for sessions that were initiated in the range from January 2017 to March
2017:
(3)
tql
1la t.e.userInput : s.beginTime == in {"2017-01".."2017-03"}
2
The examples below are equivalents and will cover all of 2017:
(4)
tql
1la t.e.userInput : s.beginTime == in {"2017-01".."2017-12"}
2
(5)
tql
1la t.e.userInput : s.beginTime == in {"2017".."2017"}
2
It is also possible to put constraints on the hours and minutes as in the example below, which finds inputs for sessions initiated from midnight to 1 a.m.:
(6)
tql
1la t.e.userInput : s.beginTime == in {"2015-01-01T00:00".."2015-01-01T01:00"}
2
As well as specifying multiple ranges in the same set-constraint:
(7)
tql
1la t.e.userInput : s.beginTime == in {monday..tuesday, thursday..friday}
2
Set-constraints used in date ranges
When date ranges are specified in set-constraints, Inquire is expanding these dates into intervals taking into account the date of the first and the last stored sessions in its database. For example:
(8)
tql
1la t.e.userInput : s.beginTime == in {january..march}
2
Considering that the first stored session is from 2017-01-01T00:00:00 and the last stored session is from 2019-12-31T23:59:59, it would be expanded in the following intervals:
- from 2017-01-01T00:00:00 to 2017-03-31T23:59:59
- from 2018-01-01T00:00:00 to 2018-03-31T23:59:59
- from 2019-01-01T00:00:00 to 2019-03-31T23:59:59
Thus, it would return all sessions from the specified month range from all years present in the stored data.
The same applies to weekdays.
Set-constraints can also be evaluated against array type values.
The example below will return user inputs present in events containing the variable a:s:words with either the arrays {"Hello", "hi"} or {"Bye"} as value.
(9)
tql
1la t.e.userInput : t.e.a:s:words == in {{"hello", "hi"}, {"Bye"}}
2
In a similar way, the example below will return user inputs present in events containing the variable a:s:words if the value of the variable contains {"hello" and "hi"} or {"Bye"}
(10)
tql
1la t.e.userInput : t.e.a:s:words == in {{"hello", "hi"}, {"Bye"}}
2
Skip-constraints
The skip-to syntax specifies the order of precedence among transitions or events by setting out a starting point and an end point, where the end point has some property. The syntax (in pseudo-code) is schematically as follows:
start -{end point constraints}> end point
end point <{end point constraints}- start
The starting and end points can be transactions or events (not necessarily in the same transaction). The constraints enclosed by {} specify the constraints the end points must fulfil. The direction of the arrow specifies whether the constraint is skipping forward or backwards in the session.
The example query below lists non-empty user inputs alongside non-empty responses immediately following them:
(1)
tql
1lu s.id, t1.e.userInput, t2.e.answerText :
2t1.e.type == "request",
3t1.e -{type=="response", answerText~=".+"}> t2.e,
4t1.e.userInput ~= ".+"
5
The second example query lists non-empty user inputs alongside non-empty responses immediately preceding them:
(2)
tql
1lu s.id, t1.e.answerText, t2.e.userInput :
2t2.e.type == "request",
3t2.e.userInput ~= ".+",
4t1.e <{type=="response", answerText~=".+"}- t2.e
5
Regular expressions
TQL supports a subset of full Perl-style regular expressions, essentially the same subset supported by Elasticsearch. Regular expressions in TQL are by definition anchored, meaning that any regex must match the entire string from beginning to end. Therefore, the conventional anchoring symbols ^ and $ are not needed.
The table below summarizes the allowed regex symbols:
Operator/Symbol | Explanation |
---|---|
. ? + * { } [ ] ( ) " \ | | Reserved symbols |
. | Any character |
? | Zero or one time |
+ | One or more times |
* | Zero or more times |
{1,3} | Min / max number of matches |
() | Grouping |
| | Alternation |
[a-z], [A-Z], [^a] | Character classes (including negation) |
\d | Any digit |
\w | Any word character |
\W | Any non-word character |
\s | A space character |
\S | A non-space character |
\\b | A word boundary |
\\t | A tabulator character |
\\n | A newline character |
\\r | A carriage return character |
Note that escape characters \b, \n, \r, and \t require double backslash escapes.
Regular expressions are supported for fields stored as strings only (not for numeric values or analyzed text). Property values are match against regular expression via the ~= (matches) and !~ (does not match) operators. The !~ operator evaluates to true either when the regex does not match or when the property is not present.
The first example below will identify user inputs that contain either "Hello" or "hello", whereas the second will identify all non-empty inputs.
(1)
tql
1lu t.e.userInput : t.e.userInput ~= ".[H|h]ello."
2
(2)
tql
1lu t.e.userInput : t.e.userInput ~= ".+"
2
The following examples are also valid. In the below cases, although the variables are declared as date and number, the use of regular expression is allowed. That is because, in the case of variables, Inquire will calculate the string value if needed before applying the constraint.
(3)
tql
1lu t.e.sv:d:dates : t.e.sv:d:dates ~= "2018.*"
2
(4)
tql
1lu t.e.sv:n:number : t.e.sv:n:number ~= "1.*"
2
(5)
tql
1lu t.e.sv:f:float : t.e.sv:f:float ~= "1.*"
2
Order of constraints
In the evaluation of a query, the TQL parser transforms the TQL expression into a directed graph that guarantees that each part of the query expression is evaluated in the correct order. Therefore, the order of constraints does not matter.
For example, the two queries below return the same results:
(1)
tql
1d e.userInput :
2s.beginTime == "2015-03",
3e.userInput ~= ".hello."
4
(2)
tql
1d e.userInput :
2e.userInput ~= ".hello.",
3s.beginTime == "2015-03"
4
Syntax and operators for diverse data types
Inquire holds diverse type of data, namely: string, integers, floats, dates, Boolean, arrays, and maps. The following table summarizes the operators that can be used with each of them.
Data type | Example | Operators | Remarks |
---|---|---|---|
String | "foo", "bar" | ==, !=, ~=, !~, exists, notexists | A quote sign followed by anything and ending with the same quote sign. The valid quote symbol is " |
Date | "2018-01-01", "2018-01", "2018" | ==, !=, exists, notexists, >, <, >=, <= | A string with an ISO-8601 formatted date or date time. This includes the following java Datetime classes: Date, Instant, LocalDate, LocalDateTime, OffsetDateTime, Time, UtilDate. |
Boolean | true, false | ==, !=, exists, notexists | A Boolean |
Integer | 1, 3094, -5 | ==, !=, exists, notexists, >, <, >=, <= | An Integer |
Double/Float | 0.42, 1.5 | ==, !=, exists, notexists, >, <, >=, <= | A number with a '.' inside. |
Array | [0,1,2] | ~~, !~~, exists, notexists, ==, !=, >, <, >=, <=, ~=, !~ | An array of some type. |
Map Object | {name: "john", surname: "doe"} | ==, !=, ~=, !, exists, notexists | Maps (and objects in general) are stored as json strings. It is possible to check if the map contains a particular value by using regular expressions, or if it is exactly the same as a given map. |
Syntax for attributes with inner spaces
In general terms, querying Teneo Studio metadata variables follows standard TQL syntax rules, e.g.:
(1)
tql
1la t.e.userInput: t.md:CATEGORY
2
However, metadata name can contain a white space. In this case, the name in the query should be written using the formulas [‘<metadata name>’]
or ["<metadata name>"]
, as in
(2)
tql
1la t.e.userInput: t.md:['CURRENT PAGE']=="http://mysite.com"
2
(3)
tql
1la t.e.userInput: t.md:["CURRENT PAGE"]==http://mysite.com
2
Transformers
Transformers are a group of TQL functions that take a variable value, execute some data manipulation, and return one or more new data values. The returned value(s) and type of data manipulation differ depending on the transformer. Transformers are used as part of a constraint in the query, and the transformed output can be returned in the selection via aliasing.
With transformers, the Teneo Inquire API may throw a null pointer exception if the type of the variable to be transformer is not correctly specified.
Dates
The catd transformer can be applied to a date field and can be used to transform its time stamp value into other date formats or to group query results by time at different levels of granularity. It accepts the four parameters below, and at least either model or pattern are mandatory.
Parameters and values are listed below:
Parameter | Default value | Possible values | Description |
---|---|---|---|
model | none | "date", "day-of-week", "month", "quarter" | A model for grouping results by time at different levels of granularity |
pattern | none | "yyyy-MM-dd", "kk", "yyyy-'w'ww", etc. | A date format string for time and date output. See Java manual for all possible values. |
locale | "en" | as for Java Locale | A locale for formatting time and date output |
timezone | "UTC" | as described by Joda-Time's DateTimeZone class | A time zone id. Can be an offset relative to UTC, e.g. "-05:00" |
Examples
Example (1) below transforms the full time stamp as stored in Teneo Inquire into a conventional year-month-day string (and is equivalent to calling pattern="yyyy-MM-dd"). Example (2) counts the number of sessions per weekday. Example (3) shows how to use relative time zone offsets to obtain results according to another time zone.
(1)
tql
1lu date : catd(model="date") s.beginTime date
2
(2)
tql
1d day : catd(model="day-of-week") s.beginTime day
2
(3)
tql
1d date : catd(model="date", timezone="-05:00") s.beginTime date
2
Trends
The trend transformer can be applied to a text field variable and transforms its values into a list of trending items. The trend algorithm is based on the Mann-Kendall non-parametric trend test, and the input arguments are:
Parameter | Default value | Description |
---|---|---|
min-tau | "0.5" | string specifying the cutoff for the absolute value of the tau correlation coefficient (min-tau) |
max-p | "0.05" | string specifying the cutoff for the p-value (max-p) |
The output values are:
- the text field variable values in the selection matching the input arguments to the trend transformer
- tau: the absolute value tau correlation coefficient
- direction: the direction of the trend (negative: "-" or positive: "+")
- p: the p-value (significance) of the trend
- z: the z-value (standard score) of the trend
The outputs can be referred to by means of aliasing.
Examples
Example (1) below returns any trending user inputs that are significant at the 0.05 level and that have a medium sized trend effect, alongside the tau value. Example (2) returns all user inputs alongside their tau value, direction of trend (if any), p-value, and z-value, ordered by tau in ascending order:
(1)
tql
1lu t.e.userInput, tau :
2t.e.type == "request",
3trend (max-p="0.05", min-tau="0.3") t.e.userInput tau
4
(2)
tql
1lu t.e.userInput, tau, direction, p, z :
2t.e.type == "request",
3trend (max-p="1", min-tau="0") t.e.userInput
4 (tau, direction, p, z)
5 tau
6
Meta parameters
Meta parameters are optional parameters that work with all commands. They generally affect the behavior of TQL, rather than operating directly on the data.
order by
The order by meta parameter orders the output data according to a mandatory variable name argument and an optional argument specifying the direction of the ordering.
Ordering is ascending by default, which can also be stated using the expression asc, but can also explicitly be set to descending using desc. For string values, ordering is alphabetical.
Examples
Examples (1) and (2) order user inputs bottom up, i.e., from less frequent first to most frequent. In contrast, example (3) orders user inputs top to bottom, i.e., most frequents first.
(1)
tql
1d e.userInput : e.type == "request" count
2
(2)
tql
1d e.userInput : e.type == "request" count
2
(3)
tql
1d e.userInput : e.type == "request" count
2
limit
The limit meta parameter takes an integer argument specifying a cap on the number of results returned. The meta parameter is specified with the TQL query. The example below returns the 10 first results of the query:
(1)
tql
1lu e.userInput : type == "request" 10
2
sample
The sample meta parameter takes an integer argument specifying how many sessions to randomly sample and return results from. The example below shows how to return results from a sample of 100 sessions:
(1)
tql
1 100 la e.userInput
2
Examples combining several constraints and transformers
Example (1) lists all unique user inputs that ended up in the Safetynet flow. Note that, by specifying that the transaction must have an event e of type request, we ensure that there will also be another event e2 present in the same transaction having the property fname (flow name). Also, the regular expression alternation pattern [S|s] allows the constraint to match flow names written either with lower or upper case "s".
(1)
tql
1lu t.e.userInput :
2t.e.type == "request", t.e2.fname ~= ".*[S|s]afetynet.*"
3
Example (2) counts the number of times that each of inputs in example (1) occurs and list the top-10 inputs that are most frequent. Note that the operator order by used in this query orders the results in ascending order (the default value), whereas the operator limit picks the top-10 results (after being ordered):
(2)
tql
1d t.e.userInput :
2 t.e.type == "request",
3 t.e2.fname ~= ".*[S|s]afetynet.*"
4 count 10
5
Example (3) counts the number of times a use input occurs per day, and order the results by date:
(3)
tql
1d date, t.e.userInput : t.e.type == "request",
2 t.e2.fname ~= ".*[S|s]afetynet.*",
3 catd(model="date") s.beginTime date
4 date
5
Example (4) lists trending inputs that are matched by the Safetynet only:
(4)
tql
1lu t.e.userInput, tau, direction, p, z :
2 t.e.type == "request",
3 t.e2.fname ~= ".*[S|s]afetynet.*",
4 trend(min-tau="0", max-p="0.05") t.e.userInput
5 (tau, direction, p, z)
6 tau
7
Other TQL commands
Sub-queries
TQL supports sub-queries, where a complete TQL query can be nested and its results can be accessed in the selection part of a superordinate TQL query. The schematic form of the sub-query syntax is:
tql
1x = @( TQL query )
2
Example (1) below lists all session ids from a sub-query that results in a unique list of session ids from those sessions with a user input containing the word "good":
(1)
tql
1la result.id :
2result = @( lu s.id id, t.e.userInput :
3t.e.type == "request",
4t.e.userInput ~= ".*good.*" )
5
Remark: It is not yet possible to use sub-queries as a set of constraints for exclusion.
Save and Source
Teneo Inquire supports two ways to save and export query results data: from the Teneo Studio frontend and using the save TQL command.
save stores query results using name as the data results identifier. When results have been saved, then the source command can retrieve those results using the parameter name and use them as the source data for another query.
For instance, query example (1) saves the results of the distribute command using the name myData:
(1)
tql
1save (name="myData") d date, t.e.userInput :
2 t.e.type == "request",
3 t.e2.fname ~= ".*[S|s]afetynet.*",
4 catd(model="date") s.beginTime
5 date date
6
Note that the data saved using the above query contains two properties: the date and the user input. To make use of that data, you need to use the source command in combination with another TQL command. The example shown in (2) retrieves and distributes the user input, whereas example (3) retrieves and distributes both the user input and the date:
(2)
tql
1d (source="myData") t.e.userInput
2
(3)
tql
1d (source="myData") date, t.e.userInput
2
Remark: you may need to remember which variables were stored when the data was saved in order to provide correct constraints when using the source command. Note that it is not possible to simply write d (source="myData")
and expect to get the date and userInput data.
Aggregate functions
TQL supports aggregation functions on saved data or sub-queries.
The aggregate functions are listed below:
Command | Returns |
---|---|
min | minimum value |
max | maximum value |
mean | arithmetic mean |
sum | sum of values |
num | number of observations |
Example (1) below returns the mean of the distribution of counts of user inputs per day from a sub-query, while example (2) returns the number of observations for a given date from a saved data set named "myData":
(1)
tql
1lu mean x.count meanCount :
2 x=@( d date, t.e.userInput :
3 t.e.type=="request", catd(model="date") s.beginTime date)
4
(2)
tql
1la (a="myData") num count, date : date == "2015-04-21"
2
Augmenters
Teneo Inquire Augmenters are applied to log data, either during import or once it has been imported, to enrich or summarize it in a format that can be later accessed by standard queries.
There are two types of Augmenters:
- Adorners add new data properties to log data in a format that can be used along original properties
- Aggregators are a pre-calculation of sum-ups of complex queries, which may have high computational costs on real time.
This section describes how to perform TQL operations with Augmenters.
Adorners
The adorn command adds new properties to sessions, transactions and events to facilitate simpler and faster queries. Adorner properties have the following syntax: <LEVEL.a.PREFIX:name>
, where
- LEVEL can refer to session s, transaction t, or event e
- a stands for adorner
- PREFIX is the data type, and
- name (following the colon) is the adorner name chosen at creation time.
The example (1) below adorns sessions with the property issueComplete, a Boolean variable set to true where the meta data variable ISSUE_INFORMATION contains the string "Complete":
(1)
tql
1adorn s.a.b:issueComplete = true :
2 exists t.e.md:ISSUE_INFORMATION,
3 t.e.md:ISSUE_INFORMATION ~= ".*Complete.*"
4
Then, the issueComplete adornment can be queried the same way as any other property.
Example (2) shows how to use it in the selection construct to obtain all session ids that were completed, while example (3) shows how to use a as a constraint to retrieve all user inputs where the session was completed:
(2)
tql
1la s.id, s.a.b:issueComplete
2
(3)
tql
1la s.t.e.userInput:
2 exists s.a.b:issueComplete,
3 s.t.e.type == "request"
4
Aggregators
The aggregate command computes sum-ups over values of properties, grouped by date. Aggregations are stored aside the rest of the data, so they cannot be queried along them in a single query. Aggregations have a name and can generate one or more <key> along three additional properties: date, week, and count. The <key> property holds the list of items that matched the TQL query, count has the size of the items list, and date and week take the session date and week values.
Example (1) creates an aggregator named dailySafetynet with a single key dailySN holding the number of inputs that fall into a safetynet trigger per day:
(1)
tql
1aggregate s:dailySN = t.id :
2 t.e1.type == "request",
3 t.e2.fname ~= ".*[s|S]afetynet.*"
4
The syntax to query aggregated values takes the aggregator name as a mandatory parameter, and any of the other properties generated by the aggregator. Example (2) shows how to retrieve all the data stored by the aggregator, grouped by date by default. Example (3) shows how to obtain the same grouped by week, and example (4) obtains the total sum-up of the count variable:
(2)
tql
1la (a= "dailySafetynet") date, week, count, s:dailySN
2
(3)
tql
1d (a= "dailySafetynet") week, count
2
(4)
tql
1ca (a= "dailySafetynet") count
2
Appendix: TQL cookbook
Lists
List all values of a variable
Problem: list all the values a variable takes on
Solution: use listUnique
on the variable
tql
1lu t.e.sv:s:userCountry : exists t.e.sv:s:userCountry
2
Note: sv:s:userCountry
is meant to be a string (s:) session variable (sv:) defined in the solution.
List unique inputs to a flow
Problem: list all the different (unique) inputs to a specific flow
Solution: use listUnique
combined with a constraint on the flow name or flow id
tql
1lu t.e.userInput : t.e.type=="request", t.e2.fname == "User says yes"
2
List trending user input words
Problem: list user input words that are showing a significant positive or negative trend
Solution: use the trend
transformer and set the cut off values to the appropriate values (recommended values below)
tql
1lu t.e.userInputWords, tau, direction, p, z :
2 t.e.type == "request",
3 trend (max-p="0.05", min-tau="0.2") t.e.userInputWords
4 (tau, direction, p, z)
5 tau
6
Note: the trend
algorithm is based on the Mann-Kendall trend test, which is a specific implementation of the general Kendall Tau correlation test
List variable values matching a pattern
Problem: list variable values that match a specific pattern, in the case of the example below: country names starting with a capital vowel
Solution: use regular expression matching on the variable value
tql
1lu t.e.sv:s:userCountry : t.e.sv:s:userCountry ~= ".[A|E|I|O|U].+"
2
Notes:
sv:s:userCountry
is meant to be a string (s:) session variable (sv:) defined in the solution- a quotation mark may be part of a variable value, hence the leading dot in the regex above
List flows coming before safetynet
Problem: list flows that are coming immediately before a safetynet flow
Solution: use listUnique
and skip-to for controlling the order events
tql
1lu t1.e.fname, t2.e.fname :
2 t1.e.pathType=="raise-flow",
3 t1.e-{pathType=="raise-flow"}>t2.e,
4 t2.e.fname ~= ".*[s|S]afetynet.*"
5
List review reason values
Problem: list the all the non-empty values of the review reason meta-data variable
Solution: use listUnique
and regex constraint on the review reason variable
tql
1lu t.e.md:REVIEW_REASON : t.e.md:REVIEW_REASON ~= ".+"
2
Notes:
- md:REVIEW_REASON is meant to be a metadata variable defined in the solution
List review reason values with user inputs and flow names
Problem: list the all the non-empty values of the review reason meta-data variable, alongside the user input and the flow name
Solution: use listUnique
and regex constraint on the review reason variable, in combination with user input and flow name
tql
1lu t.e1.userInput, t.e2.fname, t.e3.md:REVIEW\_REASON :
2 t.e1.type=="request",
3 t.e1.userInput ~= ".+",
4 exists t.e2.fname,
5 t.e3.md:REVIEW_REASON ~= ".+"
6
Notes:
- md:REVIEW_REASON is meant to be a metadata variable defined in the solution
List negative feedback comments
Problem: list the unique feedback comments that are accompanied by a negative rating
Solution: use listUnique
with a constraint on the feedback rating variable
tql
1lu t1.e.md:FEEDBACK_COMMENT, t2.e.md:FEEDBACK_RATING :
2 t1.e.md:FEEDBACK_COMMENT ~= ".+",
3 t2.e.md:FEEDBACK_RATING ~= "negative"
4
Notes:
-
md:FEEDBACK, md:FEEDBACK_RATING, and md:FEEDBACK_COMMENT are meant to be metadata variables defined in the conversational AI application.
List triggered flows per day from aggregated data
Problem: list the flows that have been triggered in a transaction for aggregated data
Solution: use listAll
on the aggregated data
tql
1la (a="test") triggeredFlowsIdPerDay
2
Notes:
- the example above assumes that an aggregator "test" has been created, with the properties triggeredFlowsIdPerDay which contains the relevant flow ids
List words matching pattern irrespective of case
Problem: list all user inputs containing "hello" irrespective of case
Solution: use listAll
on userInputWords with the ~~ operator
tql
1la t.e.userInputWords :
2 t.e.type == "request", t.e.userInputWords ~~ "hi"
3
List inputs going to a particular trigger
Problem: list all inputs going to a particular trigger
Solution: use listAll
and specify the name of the trigger, combined with skip-constraints
tql
1la t.e1.userInput, t.e2.vname :
2 t.e1.type=="request",
3 t.e2.vname=="Send SMS",
4 t.e1-{pathType=="flow-trigger"}>t.e2
5
Notes:
- the example is based on a solution that retrieves inputs going to the Send SMS trigger in the flow Send SMS to X
List answers after a particular trigger
Problem: list all answers after a particular trigger has been activated
Solution: use listAll
and specify the name of the trigger, combined with skip-constraints
tql
1la t.e1.vname, t.e2.answerText :
2 t.e1.pathType=="flow-trigger" ,
3 t.e1.vname=="Send SMS",
4 t.e1-{type=="response"}>t.e2
5
Notes:
- the example is based on a solution that retrieves inputs going to the Send SMS trigger in the flow Send SMS to X
Count and averages
Count the number of dialogues
Problem: count the number of dialogues / sessions
Solutions: use countUnique
or countAll
on the session id
tql
1cu s.id
2ca s.id
3
Count user inputs
Problem: count all user inputs
Solution: use countAll
on the user input (use countUnique to get types rather than tokens)
tql
1ca t.e.userInput : t.e.type=="request"
2
Count variable values
Problem: count the number of values found in a variable, excluding the default value
Solution: use countUnique
in combination with a sub-query
tql
1cu x.city :
2 x=@(lu t.e.sv:s:userCity city : t.e.sv:s:userCity ~= "...+")
3
Notes:
- sv:userCountry is meant to be a string (s:) session variable (sv:) defined in the solution.
Count solution responses
Problem: count all outputs
Solution: use countAll
on the output text (use countUnique to get types rather than tokens)
tql
1ca t.e.answerText :
2 t.e.type=="response",
3 exists t.e.answerText
4
Calculate mean transaction count for a time period
Problem: calculate the mean transaction count for a given time period
Solution: use the mean
prefix in combination with a sub-query
tql
1lu mean x.count meanCount :
2 x=@(lu s.id, s.transactionCount count :
3 s.beginTime=="2015-03-11")
4
Calculate mean number of empty inputs for a time period
Problem: calculate the mean number of empty user inputs for a given time period
Solution: use the mean
prefix in combination with a sub-query
tql
1lu mean x.count meanEmptyCount :
2 x=@(d date, t.e.userInput :
3 t.e.type=="request",
4 t.e.userInput == "",
5 catd(model="date") s.beginTime date,
6 s.beginTime == in {"2015-03-11".."2015-03-17"})
7
Calculate mean number of results for aggregated data
Problem: calculate the mean number of observations per date for aggregated data
Solution: use listAll
in combination with the mean prefix
tql
1la (a="test") mean count, date
2
Notes:
- this example assumes that an aggregator "test" with the properties date and count has been created
Frequency lists
To create top N lists from the solutions, use limit, e.g. limit 10 for a top-10 list (when sorted in descending order).
Most frequent user inputs
Problem: count the user inputs and sort in decreasing order
Solution: use distribute
and order by count
, specify request events
tql
1d t.e.userInput :
2 t.e.type=="request",
3 t.e.userInput ~= ".+" count
4
Most triggered flows
Problem: count the triggered flows and sort in decreasing order
Solution: use distribute
and order by count
, specify flow-trigger events
tql
1d t.e.fname :
2 t.e.pathType=="flow-trigger" count
3
Most frequent safetynet inputs
Problem: count the inputs going to a safetynet and sort in decreasing order
Solution: use distribute
and order by count
, combined search for request and flow-trigger events
tql
1d t.e.userInput :
2 t.e.type=="request",
3 t.e.userInput ~= ".+",
4 t.e2.pathType == "flow-trigger",
5 t.e2.fname ~= ".*[s|S]afetynet.*" count
6
Frequency of variable values
Problem: count the values of a variable and sort in decreasing order
Solution: use distribute
and order by count
, applied to variable
tql
1d t.e.sv:s:userCountry :
2 exists t.e.sv:s:userCountry
3 count
4
Notes:
sv:s:userCountry
is meant to be a string (s:) session variable (sv:) defined in the solution- the default value of the variable (such as "") is also listed. Use regex matching to require a longer string if "" is to be excluded
Frequency of flows triggered by a specified input
Problem: count the flows that are triggered by a specific input and sort in decreasing order
Solution: use distribute
and order by count
, in combination with skip-to
tql
1d t.e1.userInput, t.e2.fname :
2 t.e1.type=="request",
3 t.e1.userInput ~= ".*hungry.*",
4 t.e1-{pathType=="flow-trigger"}>t.e2 count
5
Notes:
- returns frequency list of user inputs containing "hungry" and triggered flows
Frequency of flow triggers
Problem: count the number of times flow triggers have been activated and sort in decreasing order
Solution: use distribute
and order by count
, specify flow-trigger events
tql
1d t.e1.fname :
2 t.e1.pathType=="flow-trigger",
3 exists t.e1.fname count
4
Frequency of sessions per day or week
Problem: count the number of sessions per day or week in a time period and sort chronologically by date
Solution: use distribute
and order by date asc
tql
1d date :
2 catd(model="date") s.beginTime date
3 date
4
tql
1d week :
2 catd(pattern="yyyy-'w'ww") s.beginTime week
3 week
4
Frequency of sessions with an input triggering safetynet by day
Problem: count the number of sessions per day, where at least one input has ended up in the Safetynet
Solution: use distribute
to count
sessions, with a constraint on the flow name
tql
1d date :
2 catd(model="date") s.beginTime date,
3 t.e1.type=="request",
4 t.e2.fname~=".*[s|S]afetynet.*"
5
Frequency of triggered flow folders
Problem: count the number of times the flows from various folders have been triggered and sort in decreasing order
Solution: use distribute
with folder
tql
1d t.e.folder :
2 t.e.pathType=="flow-trigger",
3 t.e.folder ~= ".+" count
4
Frequency of traversed safetynet transitions
Problem: count the number of times the different transitions in the safetynet flow(s) have been logged, and list the names and ids of the transitions sorted in decreasing order
Solution: use distribute
with the transition path type
tql
1d t.e.vname, t.e.vid :
2 t.e.pathType=="transition",
3 t.e.vname ~= ".+",
4 t.e.fname ~= ".*[S|s]afetynet.*" count
5
Frequency of review reason values
Problem: count the number of non-empty values of the review reason metadata variable, and sort in decreasing order
Solution: use distribute
with a regex constraint on the review reason variable
tql
1d t.e.md:REVIEW_REASON :
2 t.e.md:REVIEW_REASON ~= ".+" count
3
Notes:
- md:REVIEW_REASON is meant to be a metadata variable defined in the solution
Frequency of feedback rating
Problem: count the number of different feedback ratings, and sort in decreasing order
Solution: use distribute
on the feedback rating variable
tql
1d t.e.md:FEEDBACK_RATING :
2 t.e.md:FEEDBACK_RATING ~= ".+" count
3
Notes:
- md:FEEDBACK_RATING is meant to be a metadata variable defined in the solution
Frequency of inputs matching A OR B
Problem: count user inputs matching one of two possible values (or more)
Solution: use distribute
in combination with set constraints to emulate a logical OR syntax
tql
1d t.e.userInput :
2 t.e.type == "request",
3 t.e.userInput ~= in {"A", "B"}.
4