AQL Standard Library
Functions
General functions
now
Added in revision 1
Function now
returns the current time. Time is constant across all the script, so that all operations and queries have the same reference time.
>>> now()
2019-09-01T14:05:10Z
length
Added in revision 1
Function length
returns the number of elements in a str, a timeseries or a dict.
The first and only argument is a str, timeseries or dict
>>> length(`analytics:/path/to/data`[0])
1
merge
Added in revision 1
Function merge
returns a union of all the dicts contained in a timeseries. In case of key collision, the latest entry is kept.
The first and only argument is a timeseries of dicts
>>> `analytics:/path/to/data`[1]
timeseries{
tstamp1: dict{key1: val1, key2: val2, key3: val3}
tstamp2: dict{key1: val4, key2: val5}
}
>>> merge(_)
dict{key1: val4, key2: val5, key: val3}
deletes
Added in revision 1
Function deletes
returns a timeseries of dicts used as sets of the delete keys from the input timeseries.
Only works with unfiltered timeseries, as most filters remove the deletes entries. An empty dict as value means the update is a DeleteAll
The first and only parameter is the timeseries
>>> deletes(`analytics:/path/to/data`[200])
timeseries{
tstamp1: dict{key1: nil, key2: nil}
tstamp2: dict{} # this deletes all keys
}
equal
Added in revision 1
Function equal
performs a cross-type equality check on the given arguments using type coercions.
The first argument is a value of any type
The second argument is a value of any type
>>> equal("1", 1)
true
>>> equal(1, true)
true
>>> equal(0, true)
false
complexKey
Added in revision 1
Function complexKey
parses a string containing a literal or json object.
Numerical values without floating-point will produce an integer.
Numerical values with a floating point will produce a float64 (num).
Boolean literals will produce a boolean (bool).
Values surrounded with {} or [] will be parsed as JSON.
For all cases except float64 (num) and bool, the returned value will be of type unknown (internal interpreter type), but can be used to access complex keys in dicts.
The first and only parameter is the str to parse
>>> complexKey("1")
int(1) # AQL type is unknown
>>> complexKey("1.2")
float64(1.2) # AQL type is num
>>> complexKey("{\"key1\": 1, \"key2\": true}")
{"key1":1,"key2":true}# AQL type is unknown
>>> complexKey("[1, 2, true]")
[1,2,true] # AQL type is unknown
Dicts functions
newDict
Added in revision 1
Function newDict
returns a new empty dict.
>>> newDict()
dict{}
dictRemove
Added in revision 1
Function dictRemove
removes a given key from a dict.
The first argument is the dict
The second argument is the key to remove
>>> let d = newDict()
>>> d["key"] = 1
>>> d["key2"] = 2
>>> d
dict{"key": 1, "key2": 2}
>>> dictRemove(d, "key")
>>> d
dict{"key2": 2}
dictHasKey
Added in revision 1
Function dictHasKey
returns true if a dict contains the specified key, false if it doesn’t.
The first parameter is the dict
The second parameter is the key
>>> let d = newDict()
>>> d["key"] = 1
>>> d["key2"] = 2
>>> d
dict{"key": 1, "key2": 2}
>>> dictHasKey(d, "key")
true
>>> dictHasKey(d, "key3")
false
dictKeys
Added in revision 1
Function dictKeys
returns a timeseries with the list of keys in a dict.
The first and only parameter is the dict
>>> let d = newDict()
>>> d["key"] = 1
>>> d["key2"] = 2
>>> d
dict{"key": 1, "key2": 2}
>>> dictKeys(d)
timeseries{
0000-00-00 00:00:00.000000001: "key"
0000-00-00 00:00:00.000000002: "key2"
}
unnestTimeseries
Added in revision 4
Function unnestTimeseries
merges multiple timeseries nested in dicts, pushes them to the top level,
and returns a single flattened timeseries where the former top-level dicts are now nested within
the timeseries’ values. The input data is typically what a query using *
wildcards would return.
The first and only parameter is a dict that contains timeseries, either directly in the value, or nested in more levels of dict.
Example
>>> let ts = `analytics:/Devices/*/versioned-data/interfaces/data/*/aggregate/hardware/xcvr/1m`[1m] | recmap(2, _value | field("temperature") | field("avg"))
>>> let d = newDict() | setFields("AA", ts)
>>> d
dict{AA: dict{
HSH14280171: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.184087816704434
2022-08-16 17:11:00 +0200 CEST: 34.18519049983288
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.84759166533158
2022-08-16 17:11:00 +0200 CEST: 34.84247911778802
}
}
JAS17070003: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 30.65325390983907
2022-08-16 17:11:00 +0200 CEST: 30.65664047328105
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 27.58473123455124
2022-08-16 17:11:00 +0200 CEST: 27.597529745280074
}
}
}}
>>> unnestTimeseries(d)
timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: dict{AA: dict{
HSH14280171: dict{
Ethernet50: 34.184087816704434
Ethernet51: 34.84759166533158
}
JAS17070003: dict{
Ethernet50: 30.65325390983907
Ethernet51: 27.58473123455124
}
}}
2022-08-16 17:11:00 +0200 CEST: dict{AA: dict{
HSH14280171: dict{
Ethernet50: 34.18519049983288
Ethernet51: 34.84247911778802
}
JAS17070003: dict{
Ethernet50: 30.65664047328105
Ethernet51: 27.597529745280074
}
}}
}
>>> let b = `analytics:/Devices/JPE17191574/versioned-data/interfaces/data/Ethernet50/aggregate/hardware/xcvr/1m`[2m] | field("voltage") | field("max")
>>> let dd = newDict() | setFields("BB", b)
>>> let ddd = newDict() | setFields("DD", ts, "EE", dd)
>>> d["FF"]=ddd
>>> d
dict{
AA: dict{
HSH14280171: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.184087816704434
2022-08-16 17:11:00 +0200 CEST: 34.18519049983288
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.84759166533158
2022-08-16 17:11:00 +0200 CEST: 34.84247911778802
}
}
JAS17070003: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 30.65325390983907
2022-08-16 17:11:00 +0200 CEST: 30.65664047328105
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 27.58473123455124
2022-08-16 17:11:00 +0200 CEST: 27.597529745280074
}
}
}
FF: dict{
DD: dict{
HSH14280171: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.184087816704434
2022-08-16 17:11:00 +0200 CEST: 34.18519049983288
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 34.84759166533158
2022-08-16 17:11:00 +0200 CEST: 34.84247911778802
}
}
JAS17070003: dict{
Ethernet50: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 30.65325390983907
2022-08-16 17:11:00 +0200 CEST: 30.65664047328105
}
Ethernet51: timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:11:21.217673 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: 27.58473123455124
2022-08-16 17:11:00 +0200 CEST: 27.597529745280074
}
}
}
EE: dict{BB: timeseries{
start: 2022-08-16 17:14:06.794969 +0200 CEST
end: 2022-08-16 17:16:06.794969 +0200 CEST
2022-08-16 17:14:00 +0200 CEST: 3.2909
2022-08-16 17:15:00 +0200 CEST: 3.2909
2022-08-16 17:16:00 +0200 CEST: 3.2909
}}
}
}
>>> unnestTimeseries(d)
timeseries{
start: 2022-08-16 17:10:21.217673 +0200 CEST
end: 2022-08-16 17:16:06.794969 +0200 CEST
2022-08-16 17:10:00 +0200 CEST: dict{
AA: dict{
HSH14280171: dict{
Ethernet50: 34.184087816704434
Ethernet51: 34.84759166533158
}
JAS17070003: dict{
Ethernet50: 30.65325390983907
Ethernet51: 27.58473123455124
}
}
FF: dict{DD: dict{
HSH14280171: dict{
Ethernet50: 34.184087816704434
Ethernet51: 34.84759166533158
}
JAS17070003: dict{
Ethernet50: 30.65325390983907
Ethernet51: 27.58473123455124
}
}}
}
2022-08-16 17:11:00 +0200 CEST: dict{
AA: dict{
HSH14280171: dict{
Ethernet50: 34.18519049983288
Ethernet51: 34.84247911778802
}
JAS17070003: dict{
Ethernet50: 30.65664047328105
Ethernet51: 27.597529745280074
}
}
FF: dict{DD: dict{
HSH14280171: dict{
Ethernet50: 34.18519049983288
Ethernet51: 34.84247911778802
}
JAS17070003: dict{
Ethernet50: 30.65664047328105
Ethernet51: 27.597529745280074
}
}}
}
2022-08-16 17:14:00 +0200 CEST: dict{FF: dict{EE: dict{BB: 3.2909}}}
2022-08-16 17:15:00 +0200 CEST: dict{FF: dict{EE: dict{BB: 3.2909}}}
2022-08-16 17:16:00 +0200 CEST: dict{FF: dict{EE: dict{BB: 3.2909}}}
}
Data Analysis Functions
groupby
Added in revision 1
Function groupby
, applied to a timeseries, returns a dict with keys corresponding to the ‘group by field’ parameter,
and values corresponding to the associate method and field.
The function takes 4 parameters:
A timeseries of dicts to apply this function to
The name of the ‘group by field’ (a str)
The name of one of the supported associative methods (a str)
The name of the field whose values will be operated on by the associative method (a str)
The entries in the timeseries are grouped by the values of the field from parameter 1. For each entry, the value corresponding to the associative field of parameter 4 is obtained. This results in a map with entries of the following format:
key: values of the ‘group by field’
value: lists of values of the ‘associative field’
On each of these lists, the following associative methods can be applied:
count
: returns the length of the list (i.e. the item count)max
: returns the max entry in the listmean
: returns the mean of the values in the listmin
: returns the min entry in the listsum
: returns the sum of the entries in the list
>>> `analytics:/path/to/data`[3]
timeseries{
tstamp1: dict{"name": "name1", "value": 1}
tstamp2: dict{"name": "name2", "value": 10}
tstamp3: dict{"name": "name1", "value": 2}
tstamp4: dict{"name": "name2", "value": 11}
}
>>> let ts = _
>>> groupby(ts, "name", "mean", "value")
dict{
"name1": 1.5
"name2": 10.5
}
>>> groupby(ts, "name", "count", "value")
dict{
"name1": 2
"name2": 2
}
>>> groupby(ts, "name", "sum", "value")
dict{
"name1": 3
"name2": 21
}
histogram
Added in revision 1
Function histogram
, for a given timeseries of non-dict values, returns a dict with entries of the following format:
key: value in the timeseries (range if a timeseries of num values)
value: time-weighted frequency in the timeseries
Arguments:
A timeseries of non-dict values is the only argument to this function
>>> `analytics:/path/to/data`[3] | field("strfield")
timeseries{
start: 2019-08-31 00:00:00
end: 2019-08-31 00:12:00
2019-08-31 00:00:00: "string1"
2019-08-31 00:01:00: "string2"
2019-08-31 00:10:00: "string1"
2019-08-31 00:11:00: "string1"
}
>>> histogram(_)
dict{
"string1": 0.25
"string2": 0.75
} # the count is weighted accordingly to the intervals
>>> `analytics:/path/to/data`[5] | field("numfield")
timeseries{
start: 2019-08-31 00:00:00
end: 2019-08-31 01:00:00
2019-08-31 00:00:00: 1
2019-08-31 00:01:00: 1.01
2019-08-31 00:10:00: 1.011
2019-08-31 00:30:00: 5.2
2019-08-31 00:44:00: 5.22
2019-08-31 00:56:00: 5.23
}
>>> histogram(_)
dict{
"1.0-1.011": 0.5
"5.2-5.23": 0.5
} # the count is weighted accordingly to the intervals
dhistogram
Added in revision 1
Function dhistogram
, has a similar behaviour as histogram but its result is not time-weighted.
For a given timeseries of non-dict values, returns a dict with entries of the following format:
key: value in the timeseries (range if a timeseries of num values)
value: frequency (non-weighted count of occurences) in the timeseries
Arguments:
A timeseries of non-dict values is the only argument to this function
>>> `analytics:/path/to/data`[3] | field("strfield")
timeseries{
start: 2019-08-31 00:00:00
end: 2019-08-31 00:05:00
2019-08-31 00:00:00: "string1"
2019-08-31 00:01:00: "string2"
2019-08-31 00:10:00: "string1"
2019-08-31 00:11:00: "string1"
} # the count does not depend of the time intervals between the updates
>>> dhistogram(_)
dict{
"string1": 3
"string2": 1
} # the count does not depend of the time intervals between the updates
>>> `analytics:/path/to/data`[5] | field("numfield")
timeseries{
2019-08-31 00:00:00: 1
2019-08-31 00:01:00: 1.01
2019-08-31 00:10:00: 1.011
2019-08-31 00:30:00: 5.2
2019-08-31 00:44:12: 5.22
2019-08-31 02:01:34: 5.23
}
>>> dhistogram(_)
dict{
"1.0-1.011": 3
"5.2-5.23": 3
} # the count does not depend of the time intervals between the updates
aggregate
Added in revision 4
Function aggregate
merges multiple timeseries contained in a dict (like the result of a
wildcarded query) using the associative method specified in the second parameter. The dict must
contain timeseries, all of which must contain identical timestamps.
If one of the timeseries is empty, it will be ignored.
If some values’ timestamps are not matched in all the other non-empty timeseries of the dict, these timestamp-value pairs will not be present in the output timeseries.
aggregate
returns a simple timeseries with the aggregated data of all the input timeseries.
The first argument is the dict containing timeseries to aggregate
The second argument is the name of the associative method to apply
Like with groupby, the following associative methods can be applied:
count
: returns the length of the list (i.e. the item count)max
: returns the max entry in the list (requires the timeseries to be numerical)mean
: returns the mean of the values in the list (requires the timeseries to be numerical)min
: returns the min entry in the list (requires the timeseries to be numerical)sum
: returns the sum of the entries in the list (requires the timeseries to be numerical)
>>> let data = `analytics:/Devices/*/versioned-data/interfaces/data/*/aggregate/hardware/xcvr/15m`[1h]
>>> let avg = data | recmap(2, _value | field("temperature") | field("avg"))
>>> avg
JPE123456: dict{
Ethernet1: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 28.64315689104305
2021-11-09 13:15:00 +0000 GMT: 28.64771549594622
2021-11-09 13:30:00 +0000 GMT: 28.647003241959368
}
Ethernet2: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 26.52073192182222
2021-11-09 13:15:00 +0000 GMT: 26.57132998707
2021-11-09 13:30:00 +0000 GMT: 26.562415784963335
}
[...]
}
JPE654321: dict{
Ethernet1: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 27.872056741171672
2021-11-09 13:15:00 +0000 GMT: 26.422506200403397
2021-11-09 13:30:00 +0000 GMT: 27.889330661612725
}
Ethernet2: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 25.501376131906685
2021-11-09 13:15:00 +0000 GMT: 24.06172043150084
2021-11-09 13:30:00 +0000 GMT: 25.520567819910998
}
[...]
}
[...]
>>> let deviceAvg = avg | map(aggregate(_value, "mean"))
>>> deviceAvg
JPE123456: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 29.46781924765547
2021-11-09 13:15:00 +0000 GMT: 28.739134103556832
2021-11-09 13:30:00 +0000 GMT: 29.756429823529587
}
JPE654321: timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 27.581944406432633
2021-11-09 13:15:00 +0000 GMT: 27.60952274150811
2021-11-09 13:30:00 +0000 GMT: 27.60470951346135
}
[...]
>>> aggregate(deviceAvg, "mean") # average temp accross all interfaces of all devices
timeseries{
start: 2021-11-09 13:02:18.923904 +0000 GMT
end: 2021-11-09 13:32:18.923904 +0000 GMT
2021-11-09 13:00:00 +0000 GMT: 33.261383897237806
2021-11-09 13:15:00 +0000 GMT: 33.16722874112898
2021-11-09 13:30:00 +0000 GMT: 33.37487749955894
}
Math functions
abs
Added in revision 1
Function abs
returns the absolute value (num) of the given value.
The first and only argument \(x\) is the value (num) of which the absolute value \(\lvert x \lvert\) is wanted
>>> abs(-11)
11
>>> abs(200)
200
ceil
Added in revision 1
Function ceil
returns the closest integer (num) succeeding the given value.
The first and only argument \(x\) is the value (num) of which the ceil \(\lceil x \rceil\) is wanted
>>> ceil(12)
12
>>> ceil(12.1)
13
>>> ceil(-12.1)
-12
floor
Added in revision 1
Function floor
returns the closest integer (num) preceding the given value.
The first and only argument \(x\) is the value (num) of which the floor \(\lfloor x \rfloor\) is wanted
>>> floor(3)
3
>>> floor(3.2)
3
>>> floor(-3.2)
-4
trunc
Added in revision 1
Function trunc
returns the truncated (num) given value.
The first and only argument is the value (num) to be truncated
>>> trunc(2.6)
2
>>> trunc(-2.49)
-2
exp
Added in revision 1
Function exp
returns the exponential (num) of the given value.
The first and only argument \(x\) is the value (num) of which the exp \(e^x\) is wanted
>>> exp(0)
1
>>> exp(12.1)
179871.86225375105
factorial
Added in revision 1
Function factorial
returns the factorial (num) of the given value.
The first and only argument \(x\) is the value (num) of which the factorial \(x!\) is wanted
>>> factorial(3)
6
gcd
Added in revision 1
Function gcd
returns the greatest common divisor (num) of two given integers.
The first two arguments are the integers (num) of which the GCD is wanted
>>> gcd(25, 30)
5
log
Added in revision 1
Function log
returns the natural log (num) of the given value.
The first and only argument \(x\) is the value (num) of which the natural log \(log_e x\) is wanted
>>> log(10)
2.302585092994046
log10
Added in revision 1
Function log10
returns the decimal log (num) of the given value.
The first and only argument \(x\) is the value (num) of which the decimal log \(log_{10} x\) is wanted
>>> log10(10)
1
pow
Added in revision 1
Function pow
returns the first given value (num) to the power of the second given value.
>>> pow(3, 2)
9
>>> pow(9, 1/2)
3
round
Added in revision 1
Function round
returns the rounded (num) given value.
The first and only argument \(x\) is the value used to compute \(\lfloor x\rceil\) i.e. the rounded value (num)
>>> round(2.5)
3
>>> round(2.49)
2
sqrt
Added in revision 1
Function sqrt
returns the square root (num) of the given value.
The first and only argument \(x\) is the value (num) of which the square root \(\sqrt{x}\) is wanted
>>> sqrt(9)
3
max
Added in revision 1
Function max
returns the max value (num) in a timeseries or a dict.
The first and only argument is a timeseries or dict containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> max(_)
200
min
Added in revision 1
Function min
returns the min value (num) in a timeseries or a dict.
The first and only argument is a timeseries or dict containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> min(_)
1
formatInt
Added in revision 4
Function formatInt
formats a num into a str using the specified base. The num will be treated
as an integer and any decimal part will be truncated.
>>> formatInt(4, 2)
100
>>> formatInt(4.5, 2)
100
>>> formatInt(33, 2)
100001
>>> formatInt(15, 16)
f
>>> formatInt(29, 16)
1d
>>> type(_)
str
formatFloat
Added in revision 4
Function formatFloat
formats a num (float64
) into a str, according to the specified format and
precision.
The first argument is the num to convert
The second argument is a str of one letter describing the format:
'b'
: binary exponent'e'
: decimal exponent'f'
: no exponent'x'
: hexadecimal fraction and binary exponent
The third argument is :ref:a num specifying the precision, i.e. the number of digits after the decimal point
>>> formatFloat(15682.8729, "e", 10)
1.5682872900e+04
>>> formatFloat(15682.8729, "f", 10)
15682.8729000000
>>> formatFloat(15, "x", 3)
0x1.e00p+03
>>> formatFloat(15, "b", 3)
8444249301319680p-49
>>> type(_)
str
Stats functions
dsum
Added in revision 1
Function dsum
returns the non-weighted sum of values (num) in a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dsum(_)
216
dmean
Added in revision 1
Function dmean
returns the non-weighted mean value (num) of a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dmean(_)
54
dmedian
Added in revision 1
Function dmedian
returns the non-weighted median (num) of a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dmedian(_)
2
dpercentile
Added in revision 1
Function dpercentile
returns the non-weighted nth percentile (num) of a timeseries.
The first argument is a timeseries containing plain num values
The second argument is a num specifying the percentile. If it is greater than 100 or lower than 0, the return value will be 0.
>>> let a = `analytics:/path/to/data`[3] | field("numfield")
>>> a
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dpercentile(a, 50)
2
>>> dpercentile(a, 90)
200
dvariance
Added in revision 1
Function dvariance
returns the non-weighted statistical variance (num) of a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dvariance(_)
9503.333333333334
dstddev
Added in revision 1
Function dstddev
returns the non-weighted standard deviation (num) of a timeseries.
The first and only argument is a timeseries containing plain num values
>>> let a = `analytics:/path/to/data`[3] | field("numfield")
>>> a
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dstddev(a)
97.48504158758581
>>> sqrt(dvariance(a))
97.48504158758581
dskew
Added in revision 1
Function dskew
returns the non-weighted skewness of distribution (num) for data in a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dskew(_)
0.7431002727844832
dkurtosis
Added in revision 1
Function dkurtosis
returns the non-weighted kurtosis of distribution (num) for data in a timeseries.
The first and only argument is a timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> dkurtosis(_)
-1.6923313578244437
sum
Added in revision 1
Function sum
returns the sum of the num values in a timeseries or a dict.
If applied to a timeseries, the result is time-weighted.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> sum(_)
216
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> sum(d)
216
mean
Added in revision 1
Function mean
returns the mean of the num values in a timeseries or a dict. If applied to a timeseries, the result is time-weighted.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> mean(_)
54 # will be different from dmean if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> mean(d)
54
median
Added in revision 1
Function median
returns the median of the num values in a timeseries or a dict. If applied to a timeseries, the result is time-weighted.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> median(_)
2 # will be different from dmedian if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> median(d)
2
percentile
Added in revision 1
Function percentile
returns the time-weighted nth percentile (num) of a timeseries or a dict.
If applied to a timeseries, the result is time-weighted.
The first argument is a timeseries or a dict containing plain num values
The second argument is a num specifying the percentile. If it is greater than \(100\) or lower than \(0\), the return value will be \(0\).
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> percentile(_, 90)
200 # will be different from dpercentile if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> percentile(d, 90)
200
variance
Added in revision 1
Function variance
returns the statistical variance of the num values in a timeseries or a dict.
If applied to a timeseries, the result is time-weighted.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> variance(_)
9503.333333333334 # will be different from dvariance if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> variance(d, 90)
9503.33333333
stddev
Added in revision 1
Function stddev
returns the standard deviation of the num values in a timeseries or a dict.
If applied to a timeseries, the result is time-weighted.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> stddev(_)
97.485041588 # will be different from dstddev if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> stddev(d, 90)
97.485041588
skew
Added in revision 1
Function skew
returns the skewness of dist.n of the num values in a timeseries or a dict.
If applied to a timeseries, the result is time-weighted. If the timeseries has exactly one element, \(0\) is returned.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> skew(_)
0.7431002727844832 # will be different from dskew if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> skew(d, 90)
0.7431002727844832
kurtosis
Added in revision 1
Function kurtosis
returns the kurtosis of dist.n of the num values in a timeseries or a dict.
If applied to a timeseries, the result is time-weighted. If the timeseries has exactly one element, \(0\) is returned.
The first and only argument is a dict or timeseries containing plain num values
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
tstamp1: 13
tstamp2: 1
tstamp3: 2
tstamp4: 200
}
>>> skew(_)
0.7431002727844832 # will be different from dskew if space between the timestamps (weight) is not constant
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["key3"] = 2
>>> d["key4"] = 200
>>> skew(d, 90)
0.7431002727844832
rate
Added in revision 1
Function rate
returns a timeseries of rates computed from the initial timeseries’ num values.
The first and only argument is the input timeseries of num
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
2019-08-31 00:00:00: 1
2019-08-31 00:01:00: 10
2019-08-31 00:02:00: 50
2019-08-31 00:03:00: 110
2019-08-31 00:04:00: 230
}
>>> rate(_)
timeseries{
2019-08-31 00:00:00: 0.016666666666666666
2019-08-31 00:01:00: 0.15
2019-08-31 00:02:00: 0.6666666666666666
2019-08-31 00:03:00: 1
2019-08-31 00:04:00: 2
}
linregression
Added in revision 3
Function linregression
produces a linear fit of a timeseries of num.
The first and only argument is the input timeseries of num
It returns a dict with 4 entries slope
, intercept
, R2
and fit
. The fit
entry is a timeseries
with num values corresponding to the fitted line on the input timeseries’ timestamps. The slope
and intercept
are in seconds.
>>> `analytics:/path/to/data`[5m] | field("numfield")
timeseries{
start: 2021-10-14 13:57:55.000545 +0100 IST
end: 2021-10-14 14:02:55.000545 +0100 IST
2021-10-14 13:57:00 +0100 IST: 3.801633107494212e-05
2021-10-14 13:58:00 +0100 IST: 7.653320559746086e-05
2021-10-14 13:59:00 +0100 IST: 3.971200542852744e-05
2021-10-14 14:00:00 +0100 IST: 3.981215360110563e-05
2021-10-14 14:01:00 +0100 IST: 5.2121957107961934e-05
2021-10-14 14:02:00 +0100 IST: 3.838672949594982e-05
}
>>> linregression(_)
dict{
R2: 0.06273653863866613
fit: timeseries{
start: 2021-10-14 13:57:00 +0100 IST
end: 2021-10-14 14:02:00 +0100 IST
2021-10-14 13:57:00 +0100 IST: 5.252194027605128e-05
2021-10-14 13:58:00 +0100 IST: 5.0485322987015024e-05
2021-10-14 13:59:00 +0100 IST: 4.844870569797877e-05
2021-10-14 14:00:00 +0100 IST: 4.641208840183708e-05
2021-10-14 14:01:00 +0100 IST: 4.4375471112800824e-05
2021-10-14 14:02:00 +0100 IST: 4.2338853823764566e-05
}
intercept: 55.47126937459381
slope: -3.39436215194667e-08
}
ewlinregression
Added in revision 3
Function ewlinregression
produces a linear fit of a timeseries of num using exponentially
decaying weights. The older the value in the timeseries the smaller the weight. The latest value is
always given a weight of \(1\).
The first argument is the input timeseries of num
The second argument is the desired weight that a point with time x seconds in the past would have
the third argument is how long ago that time \(x\) is, in seconds
It returns a dict with 4 entries slope
, intercept
, R2
and fit
. The fit
entry is a timeseries
with num values corresponding to the fitted line on the input timeseries’ timestamps. The slope
and intercept
are in seconds.
>>> `analytics:/path/to/data`[5m] | field("numfield")
timeseries{
start: 2021-10-14 13:57:55.000545 +0100 IST
end: 2021-10-14 14:02:55.000545 +0100 IST
2021-10-14 13:57:00 +0100 IST: 3.801633107494212e-05
2021-10-14 13:58:00 +0100 IST: 7.653320559746086e-05
2021-10-14 13:59:00 +0100 IST: 3.971200542852744e-05
2021-10-14 14:00:00 +0100 IST: 3.981215360110563e-05
2021-10-14 14:01:00 +0100 IST: 5.2121957107961934e-05
2021-10-14 14:02:00 +0100 IST: 3.838672949594982e-05
}
>>> ewlinregression(_, 0.01, 100.0)
dict{
R2: 0.34201204121343765
fit: timeseries{
start: 2021-10-14 14:03:00 +0100 IST
end: 2021-10-14 14:08:00 +0100 IST
2021-10-14 14:03:00 +0100 IST: 4.5425229615148055e-05
2021-10-14 14:04:00 +0100 IST: 4.4509288322558405e-05
2021-10-14 14:05:00 +0100 IST: 4.359334702641604e-05
2021-10-14 14:06:00 +0100 IST: 4.267740573382639e-05
2021-10-14 14:07:00 +0100 IST: 4.176146444123674e-05
2021-10-14 14:08:00 +0100 IST: 4.0845523145094376e-05
}
intercept: 24.94748623552414
slope: -1.526568822982724e-08
}
String manipulation
strToUpper
Added in revision 1
Function strToUpper
returns uppercase version of given str.
The first and only parameter is a str to convert to uppercase
>>> strToUpper("ToUpper")
"TOUPPER"
strToLower
Added in revision 1
Function strToLower
returns lowercase version of given str.
The first and only parameter is a str to convert to lowercase
>>> strToLower("ToLower")
"TOLOWER"
strContains
Added in revision 1
Function strContains
returns whether the first str contains the second str.
Both arguments to the function are str
>>> strContains("thatistext", "is")
true
strCount
Added in revision 1
Function strCount
returns the number of occurrences of the second str in the first str.
Both arguments to the function are str
>>> strCount("tertarter", "te")
2
strIndex
Added in revision 1
Function strIndex
returns the index of the first occurrence of the second str in the first str, and -1 if it is not present.
Both arguments to the function are str
>>> strIndex("thatistext", "is")
4
strReplace
Added in revision 1
Function strReplace
returns a copy of the first str, where occurrences of the second str are replaced by the third str.
The three arguments to the function are str
>>> strReplace("thatistext", "is", "was")
"thatwastext"
strHasPrefix
Added in revision 1
Function strHasPrefix
returns whether the first str starts with the second str.
Both arguments to the function are str
>>> strHasPrefix("thatistext", "is")
false
>>> strHasPrefix("thatistext", "that")
true
strHasSuffix
Added in revision 1
Function strHasSuffix
returns whether the first str ends with the second str.
Both arguments to the function are str
>>> strHasSuffix("thatistext", "xt")
true
strSplit
Added in revision 1
Function strSplit
returns a timeseries of str. The function splits the first str into substrings, separated by the second str.
Both arguments to the function are str
>>> strSplit("that./is.text", "./")
timeseries{
0000-00-00 00:00:00.000000001: "that"
0000-00-00 00:00:00.000000002: "is.text"
}
strCut
Added in revision 4
Function strCut
returns the portion of a str between two indexes (excluding ending index).
Negative indexes start from the end of the input str.
The first argument (str) is the string from which the portion is returned
The second argument (num) is the starting index
The third argument (num) is the ending index
>>> strCut("0123456789", 1, 4)
123
>>> strCut("0123456789", -8, -2)
234567
>>> strCut("abcd", 1, 3)
bc
reFindAll
Added in revision 1
Function reFindAll
returns a timeseries of str which contains matches of the second str (regex) in the first str.
Both arguments to the function are str
>>> reFindAll("i am a string with text", "i[a-z]+")
timeseries{
0000-00-00 00:00:00.000000001: "ing"
0000-00-00 00:00:00.000000002: "ith"
}
reMatch
Added in revision 1
Function reMatch
returns whether the first str contains matches of the second str (regex).
Both arguments to the function are str
>>> reMatch("i am a string with text", "i[a-z]+")
true
reFindCaptures
Added in revision 1
Function reFindCaptures
returns a timeseries of str lists. Each list contains the full match followed by each capture
Both arguments to the function are str. The first one is the str to match, and the second is the regular expression
>>> reFindCaptures("foobarbaztootartaz", "foo")
timeseries{
0000-00-00 00:00:00.000000001: ["foo"]
}
>>> reFindCaptures("foobarbaztootartaz", "(foo)")
timeseries{
0000-00-00 00:00:00.000000001: ["foo", "foo"]
}
>>> reFindCaptures("foobarbaztootartaz", "f(oo)")
timeseries{
0000-00-00 00:00:00.000000001: ["foo", "oo"]
}
>>> reFindCaptures("foobarbaztootartaz", "(oo)")
timeseries{
0000-00-00 00:00:00.000000001: ["oo", "oo"]
0000-00-00 00:00:00.000000002: ["oo", "oo"]
}
>>> reFindCaptures("foobarbaztootartaz", "[ft](oo)")
timeseries{
0000-00-00 00:00:00.000000001: ["foo", "oo"]
0000-00-00 00:00:00.000000002: ["too", "oo"]
}
>>> reFindCaptures("foobarbaztootartaz", "([ft])(oo)")
timeseries{
0000-00-00 00:00:00.000000001: ["foo", "f", "oo"]
0000-00-00 00:00:00.000000002: ["too", "t", "oo"]
}
>>> reFindCaptures("foobarbaztootartaz", "[ft](oo).*(az)")
timeseries{
0000-00-00 00:00:00.000000001: ["foobarbaztootartaz", "oo", "az"]
}
CLI-only Functions
Warning
The functions described in this section can only be used in CLI. They cannot be called from a service or through a Web interface.
help
Added in revision 1
Function help
returns the help of all filters and functions as a formatted str.
>>> help()
# Functions
## now
- Function `now` returns the current time. Time is constant across all the script, so that all operations and queries have the same reference time
[...]
dump
Added in revision 1
Function dump
attempts to dump variables from the interpreter into a file.
The first and only argument is the path to the file (str)
>>> let myVar = 2
>>> dump("file.dump")
load
Added in revision 1
Function load
attempts to load variables into the interpreter from a file.
The first and only argument is the path to the file (str)
>>> load("file.dump")
true
>>> myVar
2
>>> let myVar = 5
>>> if load("file.dump") {
... myVar
... }
2
plot
Added in revision 1
Function plot
plots a timeseries or dict of num values.
The first argument is the timeseries or dict of num values to plot
The second argument (optional) is the path (str) to the image PNG file to write the plot to. If not specified, defaults to
plot.png
>>> plot(myTimeseriesOrDict, "myplotimg.png")
Filters
field
Added in revision 1
Filter field
applies to a timeseries of dicts. Returns a timeseries of the value at the
specified key for each entry of the timeseries that contains this field. Entries that don’t
contain the key are not in the output timeseries.
The filtered value is a timeseries of dicts
The first and only parameter is the key to keep in the dicts
>>> `analytics:/path/to/data`[1]
timeseries{
tstamp1: dict{key1: val1, key2: val2, key3: val3}
tstamp2: dict{key1: val4, key2: val5}
}
>>> _ | field("key1")
timeseries{
tstamp1: val1
tstamp2: val4
}
fields
Added in revision 3
Filter fields
applies to a dict. It filters it and returns a new dict containing only the
key/value pairs whose key is passed as parameter.
The filtered value is a dict
There is a variable (\(0\) to \(n\)) number of parameters: they are the keys to keep in the output dict
Note
If a specified key is missing from the source dict, the filter will not fail but the output dict will also be missing that key
>>> let d = `analytics:/path/to/data/*` | map(merge(_value))
>>> d
dict{
key0: dict{key1: val1, key2: val2, key3: val3}
key01: dict{key1: val4, key2: val5}
key02: dict{key1: val6, key2: val7}
}
>>> d | fields("key0", "key01")
dict{
key0: dict{key1: val1, key2: val2, key3: val3}
key01: dict{key1: val4, key2: val5}
}
>>> d | fields("k")
dict{
}
>>> d | fields()
dict{
}
>>> d | fields("key01") | map(_value | fields("key2"))
dict{
key01: dict{key2: val5}
}
setFields
Added in revision 3
Filter setFields
sets some key/value pairs in a dict. If the key already existed in the
filtered dict, its value will be replaced with the new one in the output dict (like all filters,
setFields
returns a filtered copy of the dict and does not alter the source). If the key did not
exist in the filtered dict, the key/value pair will just be added to the output dict.
The filtered value is a dict
There is a variable (0 to n) even number of parameters: they correspond to the list of key/value pairs
>>> let d = newDict() | setFields("k1", "v1", "k2", 2.3, "k3", 3)
>>> d
dict{
k1: v1
k2: 2.3
k3: 3
}
>>> d | setFields("k4", newDict() | setFields("k5", "v5"))
dict{
k1: v1
k2: 2.3
k3: 3
k4: dict{
k5: v5
}
}
>>> d
dict{
k1: v1
k2: 2.3
k3: 3
} # the source dict is not altered
applyDeletes
Added in revision 4
Filter applyDeletes
applies the deletes to a timeseries. This timeseries must be freshly returned by a query.
Most filters remove the deletes information from timeseries, so this should be called before any other filter or function.
If no argument is passed, applying a delete will remove all entries with that delete’s key that were updated prior to the delete itself. This use-case is mostly appropriate when used with the result of a query that does not contain historical data (state-only). With historical data, this would wipe deleted entries from ever having existed in the timeseries, instead of signaling the end of the entry at the moment of deletion.
If an argument is passed, then the expression defines a value that will be written at the moment of the delete for that key. This use-case is more appropriate with historical data because it will not remove entries, but instead create an entry that signals the end of the value.
The filtered value is a timeseries that still contains delete information.
The only and optional parameter is the expression. Its value can be of any type after evaluation.
Usable metavariables in the expression are:
_key
or_1
: key matching the delete
_index
: index of the delete in the timeseries
_updindex
: index of the last update for this key in the timeseries
_time
or_2
: time of the delete in the timeseries
_updtime
: time of the last update for this key in the timeseries
_value
or_3
: last value prior to the delete for the deleted key
_src
or_4
: reference to the timeseries being filtered
Example
>>> let a = `analytics:/tags/BugAlerts/Query/gNMIEnabled`[5]
>>> a
timeseries{
start: 2021-03-17 02:48:58.205235103 +0100 CET
end: 2022-10-19 13:30:33.722908 +0200 CEST
2021-03-17 02:48:58.205235103 +0100 CET: dict{
JAS12200014: true
JAS16040045: true
JAS17250006: true
JAS17250010: true
JAS17510146: true
JPE14171444: true
JPE17191574: true
SSJ17371234: true
}
2021-05-12 17:32:58.269740014 +0200 CEST: dict{
HSH14075043: true
HSH14075051: true
}
2021-11-03 17:09:46.753872494 +0100 CET: dict{
HSH14280171: true
HSH14420467: true
JPE14250224: true
JPE14383408: true
SSJ17049015: true
SSJ17374660: true
}
2021-11-11 05:09:22.273451668 +0100 CET: dict{
JAS14170008: true
JAS14210057: true
JAS17070003: true
JAS18170075: true
JPE14120478: true
JPE19280519: true
}
2022-02-18 23:08:10.204460235 +0100 CET: dict{
2568DB4A33177968A78C4FD5A8232159: true
6323DA7D2B542B5D09630F87351BEA41: true
BAD032986065E8DC14CBB6472EC314A6: true
CD0EADBEEA126915EA78E0FB4DC776CA: true
}
2022-02-22 00:48:45.347884243 +0100 CET: dict{0123F2E4462997EB155B7C50EC148767: true}
2022-07-18 18:10:07.772750473 +0200 CEST: dict{JPE20244151: true}
}
>>> deletes(a)
timeseries{
start: 2021-03-17 02:48:58.205235103 +0100 CET
end: 2022-10-19 13:30:33.722908 +0200 CEST
2021-11-23 11:09:21.716099165 +0100 CET: dict{
HSH14075043: <nil>
HSH14075051: <nil>
HSH14280171: <nil>
HSH14420467: <nil>
JAS14170008: <nil>
JAS14210057: <nil>
JAS16040045: <nil>
JAS17070003: <nil>
JAS17250006: <nil>
JAS17250010: <nil>
JAS17510146: <nil>
JAS18170075: <nil>
JPE14120478: <nil>
JPE14171444: <nil>
JPE14250224: <nil>
JPE14383408: <nil>
JPE17191574: <nil>
JPE19280519: <nil>
SSJ17049015: <nil>
SSJ17371234: <nil>
SSJ17374660: <nil>
}
2022-02-22 00:48:45.347884243 +0100 CET: dict{
2568DB4A33177968A78C4FD5A8232159: <nil>
6323DA7D2B542B5D09630F87351BEA41: <nil>
BAD032986065E8DC14CBB6472EC314A6: <nil>
CD0EADBEEA126915EA78E0FB4DC776CA: <nil>
}
}
>>> a | applyDeletes()
timeseries{
start: 2021-03-17 02:48:58.205235103 +0100 CET
end: 2022-10-19 13:30:33.722908 +0200 CEST
2021-03-17 02:48:58.205235103 +0100 CET: dict{JAS12200014: true}
2022-02-22 00:48:45.347884243 +0100 CET: dict{0123F2E4462997EB155B7C50EC148767: true}
2022-07-18 18:10:07.772750473 +0200 CEST: dict{JPE20244151: true}
}
>>> a | applyDeletes(_key+" is deleted, its value was " + str(_value))
timeseries{
start: 2021-03-17 02:48:58.205235103 +0100 CET
end: 2022-10-19 13:30:33.722908 +0200 CEST
2021-03-17 02:48:58.205235103 +0100 CET: dict{
JAS12200014: true
JAS16040045: true
JAS17250006: true
JAS17250010: true
JAS17510146: true
JPE14171444: true
JPE17191574: true
SSJ17371234: true
}
2021-05-12 17:32:58.269740014 +0200 CEST: dict{
HSH14075043: true
HSH14075051: true
}
2021-11-03 17:09:46.753872494 +0100 CET: dict{
HSH14280171: true
HSH14420467: true
JPE14250224: true
JPE14383408: true
SSJ17049015: true
SSJ17374660: true
}
2021-11-11 05:09:22.273451668 +0100 CET: dict{
JAS14170008: true
JAS14210057: true
JAS17070003: true
JAS18170075: true
JPE14120478: true
JPE19280519: true
}
2021-11-23 11:09:21.716099165 +0100 CET: dict{
HSH14075043: HSH14075043 is deleted, its value was true
HSH14075051: HSH14075051 is deleted, its value was true
HSH14280171: HSH14280171 is deleted, its value was true
HSH14420467: HSH14420467 is deleted, its value was true
JAS14170008: JAS14170008 is deleted, its value was true
JAS14210057: JAS14210057 is deleted, its value was true
JAS16040045: JAS16040045 is deleted, its value was true
JAS17070003: JAS17070003 is deleted, its value was true
JAS17250006: JAS17250006 is deleted, its value was true
JAS17250010: JAS17250010 is deleted, its value was true
JAS17510146: JAS17510146 is deleted, its value was true
JAS18170075: JAS18170075 is deleted, its value was true
JPE14120478: JPE14120478 is deleted, its value was true
JPE14171444: JPE14171444 is deleted, its value was true
JPE14250224: JPE14250224 is deleted, its value was true
JPE14383408: JPE14383408 is deleted, its value was true
JPE17191574: JPE17191574 is deleted, its value was true
JPE19280519: JPE19280519 is deleted, its value was true
SSJ17049015: SSJ17049015 is deleted, its value was true
SSJ17371234: SSJ17371234 is deleted, its value was true
SSJ17374660: SSJ17374660 is deleted, its value was true
}
2022-02-18 23:08:10.204460235 +0100 CET: dict{
2568DB4A33177968A78C4FD5A8232159: true
6323DA7D2B542B5D09630F87351BEA41: true
BAD032986065E8DC14CBB6472EC314A6: true
CD0EADBEEA126915EA78E0FB4DC776CA: true
}
2022-02-22 00:48:45.347884243 +0100 CET: dict{
2568DB4A33177968A78C4FD5A8232159: 2568DB4A33177968A78C4FD5A8232159 is deleted, its value was true
6323DA7D2B542B5D09630F87351BEA41: 6323DA7D2B542B5D09630F87351BEA41 is deleted, its value was true
BAD032986065E8DC14CBB6472EC314A6: BAD032986065E8DC14CBB6472EC314A6 is deleted, its value was true
CD0EADBEEA126915EA78E0FB4DC776CA: CD0EADBEEA126915EA78E0FB4DC776CA is deleted, its value was true
}
2022-02-22 00:48:45.347884243 +0100 CET: dict{0123F2E4462997EB155B7C50EC148767: true}
2022-07-18 18:10:07.772750473 +0200 CEST: dict{JPE20244151: true}
}
renameFields
Added in revision 3
Filter renameFields
renames some keys in a dict. The keys which are not specified in the
arguments will be kept in the output dict. Use the fields filter to remove them.
The filtered value is a dict
There is a variable (\(0\) to \(n\)) even number of parameters: they correspond to the list of old-key/new-key pairs
Note
If a specified key is missing from the source dict, the filter will not fail and that pair will just be ignored
>>> let d = `analytics:/path/to/data/*` | map(merge(_value))
>>> d
dict{
key0: dict{key1: val1, key2: val2, key3: val3}
key01: dict{key1: val4, key2: val5}
}
>>> d | renameFields("key0", "newkey0")
dict{
newkey0: dict{key1: val1, key2: val2, key3: val3}
key01: dict{key1: val4, key2: val5}
}
>>> d | renameFields("key0", "newkey0", "key01", "newkey01")
dict{
newkey0: dict{key1: val1, key2: val2, key3: val3}
newkey01: dict{key1: val4, key2: val5}
}
>>> d | fields("key01") | map(_value | renameFields("key2", "newkey2"))
dict{
key01: dict{key1: val4, newkey2: val5}
}
where
Added in revision 1
Filter where
returns a filtered timeseries or dict containing exclusively the entries of the input where
the predicate passed as parameter is true.
The first and only parameter is the predicate. It is an expression, the value of which must be a boolean after evaluation.
Usable metavariables in the predicate for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))
_time
or_2
: timestamp of the current element
_value
or_3
: value of the current element
_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the predicate for dicts are:
_key
or_1
: key of the current element
_value
or_2
: value of the current element
_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> `analytics:/path/to/data`[3] | field("key1")
timeseries{
tstamp1: 1
tstamp2: 2
tstamp3: 3
tstamp4: 4
}
>>> _ | where(_value >= 3)
timeseries{
tstamp3: 3
tstamp4: 4
}
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["k3"] = 1
>>> d["k4"] = 1
>>> d | where(strContains(_key, "key"))
dict{
"key1": 13
"key2": 1
}
map
Added in revision 1
Filter map
returns a timeseries or dict containing the results of the expression passed as parameter applied to each entry of the filtered timeseries or dict.
The first and only parameter is the expression. Its value can be of any type after evaluation.
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_2
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> `analytics:/path/to/data`[3]
timeseries{
tstamp1: dict{key1: 1, key2: 12, key3: 11}
tstamp2: dict{key1: 2, key2: 123}
tstamp3: dict{key1: 3, key2: 78, key3: 42}
tstamp4: dict{key1: 4, key2: 68}
}
>>> _ | map(_value["key1"] + 1)
timeseries{
tstamp1: 2
tstamp2: 3
tstamp3: 4
tstamp4: 5
}
>>> let d = newDict()
>>> d["key1"] = 13
>>> d["key2"] = 1
>>> d["k3"] = 1
>>> d["k4"] = 1
>>> d | map(_key + "l")
dict{
"key1": key1l
"key2": key2l
"k3": k3l
"k4": k4l
}
>>> d | map(_value^2)
dict{
"key1": 169
"key2": 1
"k3": 1
"k4": 1
}
mapne
Added in revision 1
Filter mapne
(map-not-empty) returns a timeseries or dict containing the results of the
expression passed as first parameter applied to the result of the expression passed as second parameter
if its result is not empty. This applies to each entry of the filtered timeseries or dict.
The first parameter is the main expression. Its value can be of any type after evaluation.
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: result of the second expression applied to the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for :ref:`dict`s are:
_key
or_1
: key of the current element_value
or_2
: result of the second expression applied to the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
the second parameter is the filtering expression. Its value can be of any type after evaluation.
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at 0)_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_3
value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> `analytics:/path/to/*/data/with/wildcard`[3]
dict {
pathElement1: timeseries{t1:1, t2:2, t3:3, t4:4}
pathElement2: timeseries{t5:5, t6:6, t7:7, t8:8}
pathElement3: timeseries{}
pathElement4: timeseries{t9:9, t10:10, t11:11, t12:12}
}
>>> _ | map(mean(_value))
error: cannot compute mean of empty timeseries
>>> _ | mapne(mean(_value), _value)
dict {
pathElement1: 2.5
pathElement2: 6.5
pathElement4: 10.5
}
>>> `analytics:/path/to/data`[3]
timeseries{
tstamp1: dict{k1:1, k2:2, k3:3, k4:4}
tstamp2: dict{k1:1, k2:2, k3:3, k4:4}
tstamp3: dict{}
tstamp4: dict{k1:1, k2:2, k3:3, k4:4}
}
>>> _ | map(mean(_value))
error: cannot compute mean of empty dict
>>> _ | mapne(mean(_value) + 12, _value)
timeseries{
tstamp1: 14.5
tstamp2: 14.5
tstamp4: 14.5
}
recmap
Added in revision 1
Filter recmap
returns a timeseries or dict containing the results of the expression passed as parameter applied to each
entry of the filtered timeseries or dict, at the specified depth.
The first parameter is the recursion depth (num).
The second parameter is the expression. Its value can be of any type after evaluation.
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_2
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> `analytics:/path/to/*/data/with/*/2/wildcards`
dict {
pe1: dict{pe1.1: timeseries{1, 2, 3}, pe1.2: timeseries{1, 2, 3}}
pe2: dict{pe2.1: timeseries{1, 2, 3}, pe2.2: timeseries{1, 2, 3}}
pe3: dict{pe3.1: timeseries{1, 2, 3}, pe3.2: timeseries{1, 2, 3}}
} # we want the same recursion depth for every branch here, and stop at the timeseries level
>>> let data = _
>>> data | map(_value | map(mean(_value)))
dict {
pe1: dict{pe1.1: 2, pe1.2: 2}
pe2: dict{pe2.1: 2, pe2.2: 2}
pe3: dict{pe3.1: 2, pe3.2: 2}
} # nested map filters work but are very verbose
>>> data | recmap(2, mean(_value))
dict {
pe1: dict{pe1.1: 2, pe1.2: 2}
pe2: dict{pe2.1: 2, pe2.2: 2}
pe3: dict{pe3.1: 2, pe3.2: 2}
}
# recmap is much clearer.
topK
Added in revision 3
Filter topK
filters the collection to keep only the k highest values. This filter can be
applied to a timeseries or a dict.
The first parameter is the
k
parameter, which is the number of values to keep in the filtered collection.The second parameter is an expression that returns for each entry of the collection the value to compare. The return type of this expression must be comparable (num, str, time, or duration)
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_2
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> let data = `analytics:/path/to/some/*/data` | map(merge(_value))
>>> data
dict{
Ethernet49/1: dict{
in: 11.845057565692196
out: 20.816078774499992
}
Ethernet49/5: dict{
in: 4.021321282808746
out: 8.868898231943206
}
Ethernet51/1: dict{
in: 2.1800167411644353
out: 2.413745251460854
}
Ethernet51/2: dict{
in: 3.126216167169341
out: 26.05024018915018
}
Ethernet51/3: dict{
in: 54.1046901332212
out: 5.035469519006775
}
Ethernet51/4: dict{
in: 7.313228804713885
out: 4.899238295809337
}
Ethernet8: dict{
in: 0
out: 71.6547381850231
}
Management1: dict{
in: 6.139184309225689
out: 0.7010378175218949
}
Port-Channel512: dict{
in: 7.864572656164906
out: 14.724350983923758
}
Port-Channel532: dict{
in: 16.652391153117858
out: 9.562088032011452
}
}
>>> data | topK(2, _value["in"])
dict{
Ethernet51/3: dict{
in: 54.1046901332212
out: 5.035469519006775
}
Port-Channel532: dict{
in: 16.652391153117858
out: 9.562088032011452
}
}
>>> data | map(_value["in"]) | topK(2, _value)
dict{
Ethernet51/3: 54.1046901332212
Port-Channel532: 16.652391153117858
}
bottomK
Added in revision 3
Filter bottomK
filters the collection to keep only the k lowest values. This filter can be
applied to a timeseries or a dict.
The first parameter is the
k
parameter, which is the number of values to keep in the filtered collection.The second parameter is an expression that returns for each entry of the collection the value to compare. The return type of this expression must be comparable (num, str, time, or duration)
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_2
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> let data = `analytics:/path/to/some/*/data` | map(merge(_value))
>>> data
dict{
Ethernet49/1: dict{
in: 11.845057565692196
out: 20.816078774499992
}
Ethernet49/5: dict{
in: 4.021321282808746
out: 8.868898231943206
}
Ethernet51/1: dict{
in: 2.1800167411644353
out: 2.413745251460854
}
Ethernet51/2: dict{
in: 3.126216167169341
out: 26.05024018915018
}
Ethernet51/3: dict{
in: 54.1046901332212
out: 5.035469519006775
}
Ethernet51/4: dict{
in: 7.313228804713885
out: 4.899238295809337
}
Ethernet8: dict{
in: 0
out: 71.6547381850231
}
Management1: dict{
in: 6.139184309225689
out: 0.7010378175218949
}
Port-Channel512: dict{
in: 7.864572656164906
out: 14.724350983923758
}
Port-Channel532: dict{
in: 16.652391153117858
out: 9.562088032011452
}
}
>>> data | bottomK(2, _value["in"])
dict{
Ethernet51/1: dict{
in: 2.1800167411644353
out: 2.413745251460854
}
Ethernet8: dict{
in: 0
out: 71.6547381850231
}
}
>>> data | map(_value["in"]) | bottomK(2, _value)
dict{
Ethernet51/1: 2.1800167411644353
Ethernet8: 0
}
deepmap
Added in revision 1
Filter deepmap
returns a timeseries or dict containing the results of the expression
passed as parameter applied to each entry of the filtered timeseries or dict, which can
contain nested timeseries or dicts.
The first and only parameter is the expression. Its value can be of any type after evaluation.
Metavariables are applicable to the collection containing the leaf node to which the expression is applied, which can be nested under several layers.
Usable metavariables in the expression for timeseries are:
_index
or_1
: index of the current element (starting at \(0\))_time
or_2
: timestamp of the current element_value
or_3
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
Usable metavariables in the expression for dicts are:
_key
or_1
: key of the current element_value
or_2
: value of the current element_src
or_4
(revision 4+): reference to the timeseries or dict being filtered
>>> `analytics:/path/to/*/data/with/wildcard`[3]
dict {
pathElement1: timeseries{t1:1, t2:2, t3:3, t4:4}
pathElement2: timeseries{t5:5, t6:6, t7:7, t8:8}
pathElement3: timeseries{dict{k10:10}, dict{k11:11}}
}
>>> _ | deepmap(_value + 1)
dict {
pathElement1: timeseries{t1:2, t2:3, t3:4, t4:5}
pathElement2: timeseries{t5:6, t6:7, t7:8, t8:9}
pathElement3: timeseries{dict{k10:11}, dict{k11:12}}
} # recursion depth can be different between branches, deepmap will recurse as long as the value is either a dict or timeseries
resample
Added in revision 1
Filter resample
returns a timeseries resampled with the given duration as constant interval.
CloudVision timeseries are state-based, so any value in the output timeseries will be the latest
value prior to the output timestamp in the original timeseries.
The first and only parameter, of type duration, specifies the interval of the output timeseries.
>>> `analytics:/path/to/data`[3] | field("numfield")
timeseries{
2019-08-31 00:00:00: 13
2019-08-31 00:06:23: 1
2019-08-31 00:08:29: 2
2019-08-31 00:11:43: 200
}
>>> _ | resample(2m)
timeseries{
2019-08-31 00:00:00: 13
2019-08-31 00:02:00: 13
2019-08-31 00:04:00: 13
2019-08-31 00:06:00: 13
2019-08-31 00:08:00: 13
2019-08-31 00:10:00: 2
2019-08-31 00:12:00: 200
}