TQL Cookbook

Lists

List all values of a variable

Use listUnique on the variable:

lu t.e.sv:s:userCountry : exists t.e.sv:s:userCountry

sv:s:userCountry is meant to be a string (s:) session variable (sv:) defined in the bot

List unique inputs to a flow

Use listUnique combined with a constraint on the flow name or flow ID:

lu t.e.userInput : t.e.type=="request", t.e2.fname == "User says yes"

List user input words showing positive or negative trend

Use the trend transformer and set the cut off values to the appropriate values (recommended values below):

lu t.e.userInputWords, tau, direction, p, z :
    t.e.type == "request",
    trend (max-p="0.05", min-tau="0.2") t.e.userInputWords as (tau, direction, p, z)
order by tau

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

For this example, list country names starting with a capital vowel.

Use regular expression matching on the variable value:

lu t.e.sv:s:userCountry : t.e.sv:s:userCountry ~= ".[A|E|I|O|U].+"

sv:userCountry is meant to be a string (s:) session variable (sv:) defined in the bot.

A quotation mark may be part of a variable value, hence the leading dot in the regex above.

List flows immediately preceding safetynet

Use listUnique and skip-to for controlling the order events:

lu t1.e.fname, t2.e.fname :
    t1.e.pathType=="raise-flow",
    t1.e-{pathType=="raise-flow"}>t2.e,
    t2.e.fname ~= ".*[s|S]afetynet.*"

List review reason meta-data values

Use listUnique and regex constraint on the review reason variable:

lu t.e.md:REVIEW_REASON : t.e.md:REVIEW_REASON ~= ".+"

md:REVIEW_REASON is meant to be a metadata variable defined in the solution.

List review reason meta-data values with user inputs and flow names

Use listUnique and regex constraint on the review reason variable, in combination with user input and flow name:

lu t.e1.userInput, t.e2.fname, t.e3.md:REVIEW_REASON :
    t.e1.type=="request",
    t.e1.userInput ~= ".+",
    exists t.e2.fname,
    t.e3.md:REVIEW_REASON ~= ".+"

md:REVIEW_REASON is meant to be a metadata variable defined in the solution.

List negative feedback comments accompanied by a negative rating

Use listUnique with a constraint on the feedback rating variable:

lu t1.e.md:FEEDBACK_COMMENT, t2.e.md:FEEDBACK_RATING :
    t1.e.md:FEEDBACK_COMMENT ~= ".+",
    t2.e.md:FEEDBACK_RATING ~= "negative"

md:FEEDBACK, md:FEEDBACK_RATING, and md:FEEDBACK_COMMENT are meant to be metadata variables defined in the solution.

List user inputs matching a language object condition

Use listUnique with the matches-condition transformer:

lu t.e.userInput :
    t.e.type == "request",
    t.e.userInput matches-condition (solution="en_tlr", condition = "%WHO.FW.LEX + %BE.VB.LEX")

The example above shows that the condition parameter accepts any valid combination of language objects and condition operators. However, the same condition could be rewritten using a single language object: “WHO_IS.PHR”. Note also that this query only works if a solution "en_tlr" has been associated with the log data.

List language objects matching user inputs

This can be used to analyze how to improve conditions in the solution according to the matching LOBs.

Use listUnique with the matching-lobs transformer:

lu t.e.userInput, lob, used-words :
    matching-lobs(solution="en_tlr") t.e.userInput as (lob, used-words)

Note that this query only works if a solution "en_tlr" has been associated with the log data.

List triggered flows per day from aggregated data

Use listAll on the aggregated data:

la (a="test") triggeredFlowsIdPerDay

The example above assumes that an aggregator "test" has been created, with the property triggeredFlowsIdPerDay which contains the relevant flow IDs.

List words matching pattern irrespective of case

In this case, list all user inputs containing "hello" irrespective of case.

Use listAll on userInputWords with the ~~ operator:

la t.e.userInputWords :
    t.e.type == "request", t.e.userInputWords ~~ "hello"

List inputs going to a particular trigger

Use listAll and specify the name of the trigger, combined with skip-constraints:

la t.e1.userInput, t.e2.vname :
    t.e1.type=="request",
    t.e2.vname=="Send SMS",
    t.e1-{pathType=="flow-trigger"}>t.e2

The example is based on a solution that retrieves inputs going to the Send SMS trigger.

List answers after a particular trigger

Use listAll and specify the name of the trigger, combined with skip-constraints:

la t.e1.vname, t.e2.answerText :
    t.e1.pathType=="flow-trigger" ,
    t.e1.vname=="Send SMS",
    t.e1-{type=="response"}>t.e2

The example is based on a solution that retrieves inputs going to the Send SMS trigger.

Count and averages

Count the number of dialogues

Use countUnique or countAll on the session id:

cu s.id
ca s.id

Count user inputs

Use countAll on the user input (use countUnique to get types rather than tokens):

ca t.e.userInput : t.e.type=="request"

Count number of values found in a variable

Use countUnique in combination with a sub-query:

cu x.city :
    x=@(lu t.e.sv:s:userCity as city : t.e.sv:s:userCity ~= "...+")

sv:userCountry is meant to be a string (s:) session variable (sv:) defined in the solution.

Count bot responses

Use countAll on the output text (use countUnique to get types rather than tokens):

ca t.e.answerText :
    t.e.type=="response",
    exists t.e.answerText

Calculate mean transaction count for a time period

Use the mean prefix in combination with a sub-query:

lu mean x.count as meanCount :
    x=@(lu s.id, s.transactionCount as count : s.beginTime=="2015-03-11")

Calculate mean number of empty inputs for a time period

Use the mean prefix in combination with a sub query:

lu mean x.count as meanEmptyCount :
    x=@(d date, t.e.userInput :
        t.e.type=="request",
        t.e.userInput == "",
        catd(model="date") s.beginTime as date,
        s.beginTime == in {"2015-03-11".."2015-03-17"})

Calculate mean number of results for aggregated data

Use listAll in combination with the mean prefix:

la (a="test") mean count, date

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

Use distribute and order by count, specify request events:

d t.e.userInput :
    t.e.type=="request",
    t.e.userInput ~= ".+"
order by count desc

Most triggered flows

Use distribute and order by count, specify flow-trigger events:

d t.e.fname :
    t.e.pathType=="flow-trigger" 
order by count desc

Most frequent safetynet inputs

Use distribute and order by count, combined search for request and flow-trigger events:

d t.e.userInput :
    t.e.type=="request",
    t.e.userInput ~= ".+",
    t.e2.pathType == "flow-trigger",
    t.e2.fname ~= ".*[s|S]afetynet.*" 
order by count desc

Frequency of variable values

Count the number of values of a variable and sort in decreasing order.

Use distribute and order by count, applied to variable:

d t.e.sv:s:userCountry :
    exists t.e.sv:s:userCountry
order by count desc

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

Count the number of flows that are triggered by a specific input and sort in decreasing order.

Use distribute and order by count, in combination with skip-to:

d t.e1.userInput, t.e2.fname :
    t.e1.type=="request",
    t.e1.userInput ~= ".*hungry.*",
    t.e1-{pathType=="flow-trigger"}>t.e2 
order by count desc

Returns frequency list of user inputs containing "hungry" and triggered flows.

Frequency of flow triggers

Count the number of times flow triggers have been activated and sort in decreasing order.

Use distribute and order by count, specify flow-trigger events:

d t.e1.fname :
    t.e1.pathType=="flow-trigger",
    exists t.e1.fname 
order by count desc

Frequency of sessions per specified time period

Count the number of sessions per e.g. day or week and sort chronologically by date.

Use distribute and order by date asc:

d date :
    catd(model="date") s.beginTime as date
order by date asc
d week :
    catd(pattern="yyyy-'w'ww") s.beginTime as week
order by week asc

Frequency of sessions with an input triggering Safetynet by day

Use distribute to count sessions, with a constraint on the flow name:

d date :
    catd(model="date") s.beginTime as date,
    t.e1.type=="request",
    t.e2.fname~=".*[s|S]afetynet.*"

Frequency of triggered flow folders

Count the number of times the flows from various folders have been triggered and sort in decreasing order.

Use distribute with folder:

d t.e.folder :
    t.e.pathType=="flow-trigger",
    t.e.folder ~= ".+"
order by count desc

Frequency of traversed Safetynet transitions

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.

Use distribute with the transition path type:

d t.e.vname, t.e.vid :
    t.e.pathType=="transition",
    t.e.vname ~= ".+",
    t.e.fname ~= ".*[S|s]afetynet.*"
order by count desc

Frequency of review reason values

Count the number of non-empty values of the review reason metadata variable, and sort in decreasing order.

Use distribute with a regex constraint on the review reason variable:

d t.e.md:REVIEW_REASON :
    t.e.md:REVIEW_REASON ~= ".+"
order by count desc

md:REVIEW_REASON is meant to be a metadata variable defined in the solution.

Frequency of feedback rating

Count the number of different feedback ratings, and sort in decreasing order.

Use distribute on the feedback rating variable:

d t.e.md:FEEDBACK_RATING :
    t.e.md:FEEDBACK_RATING ~= ".+"
order by count desc

md:FEEDBACK_RATING is meant to be a metadata variable defined in the solution.

Frequency of inputs matching A OR B

Count user inputs matching one of two or more possible values.

Use distribute in combination with set constraints to emulate a logical OR condition:

d t.e.userInput :
    t.e.type == "request",
    t.e.userInput ~= in {"A", "B"}

Was this page helpful?