Understanding operationalWindow
The ExpressionEngineFunction#operationalWindow is a method provided by the ExpressionEngineFunction to be used in metrics.
The ExpressionEngineFunction#operationalWindow accepts two sets of time series data as input, one representing the data to perform the aggregation on, and the other representing the interval when the data is operational. The return value is a set set of time series data representing every value in the output of an aggregation function (for example, sum, max, min, avg) which is applied to data spanning an operational time window.
The ExpressionEngineFunction#operationalWindow function can be used to answer a question, for example: "Looking at temperature data over the last 50 hours an aircraft was in the air (including data from when the plane was grounded), track the average temperature of the right wing over a period where each window aggregates 2 hours of in-flight data."
How it works
ExpressionEngineFunction#operationalWindow is calculated by applying the aggFunc on an operationalSpan of values in dataTs from a range of time starting at operationalOffset where operationalOffset and operationalSpan determine the true absolute offset and span from the data in operationalTs.
Parameters
The function signature for operationalWindow is as follows:
operationalWindow(aggFunc, dataTs, operationalTs, operationalOffset, operationalSpan)
aggFunc- name of the aggregation function
- This is the function that specifies how to aggregate the values in the specified window.
- Supported values are
'SUM','AVG','MIN','MAX'.
dataTs- time series representing the data over which the aggregation is performed.
operationalTs- time series indicating which intervals the mechanism producing the above
dataTsis operational.
- time series indicating which intervals the mechanism producing the above
operationalOffset- start aggregating the i-th window,
operationalOffsetoperational points after the i-th value. - this value is used to derive the true or absolute offset, for each distinct window, from the data found in the
operationalTs. - Note:
operationalOffsetcan be a negative offset.
- start aggregating the i-th window,
operationalSpan- The size of the window:
- For each value in the output time series, the
aggFuncis applied over a window of sizeoperationalSpan. - this value is used to derive the true or absolute span, for each distinct window, from the data found in the
operationalTs. operationalSpanis only optional in the case whereoperationalOffsetis negative. If not specified, the span is calculated variably from the negative operational offset index to current window index: for example, the i-th value in the output series is calculated by applying the aggregation function over only theoperationalOffset + ithvalue oftimeseries.
- For each value in the output time series, the
- The size of the window:
Examples
Consider a metric that calculates the number of times an airplane is serviced in the previous 3 flight hours. Given the data for a metric ServiceCount for an airplane and metric InFlight representing the intervals the plane is in flight both at an HOUR granularity from "2018-01-01T00:00:00" until "2018-01-02T00:00:00":
dataTs data (Indicating how many times a plane was serviced each hour):
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]operationalTs data (Indicating which hours the plane is in flight):
[1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]There are a number of different insights (described below in more detail) collected about the above data.
Zero and positive offsets
First, it is possible to try and find the number of times a plane was serviced in the next 3 hours a plane is operational. Using the operationalWindow function, define a metric ServiceCountFollowingThreeOperationalHours with the expression: operationalWindow('SUM', ServiceCount, InFlight, 0, 3)'. Notice that the operationalOffset in this case is '0', and the operationalSpan is '3' indicating that the aggregation is performed on all data from the current time window to the interval where the plane has been in the air for 3 hours. To better illustrate this, use the above data.
From the operational data, note the window time '0', the plane is in the air on the 0th, 3rd, and 5th hours of the time range. By aggregating all data within this time-span, it is possible to collect a SUM for that window spanning from index '0' to index '5' to be 0 + 1 + 2 + 3 + 4 + 5 => 15.
Now, from the perspective of window time '1', the plane is now in the air on the 3rd, 5th and 6th hours of the time range. By aggregating data in this new time-span, collect a SUM for that window spanning from index '1' (current window time) to index '6' (last hour the plane is in flight within the operational span) for a total of 1 + 2 + 3 + 4 + 5 + 6 => 21.
Extrapolate this process out to find that the resulting timeseries produces data that looks like: [15.0, 21.0, 20.0, 18.0, 39.0, 35.0, 40.0, 57.0, ...].
Negative offset
The most common use case for this expression is likely be with a negative offset. If a user wants to find the total service count over the last 3 hours a plane was operational, they would use a negative offset. Being the most commonly used operation, it also comes in two flavors:
Negative offset flavor #1
The first flavor of negative offset works similarly to how zero and positive offset work, where an operationalSpan is also provided like: operationalWindow('SUM', ServiceCount, InFlight, -2, 3)'.
Something interesting to notice is that from the above provided operationalTs data, there isn't actually any operational data to aggregate until time window '4' which is to say that the plane has not been in flight for a total of two hours until time window '4' so that would be the first window to perform an aggregation on.
Starting at window time '4', by jumping an offset of '-2' or two operational hours in the past, you land on the 0th hour and by aggregating all data within a three operational hour time-span starting at the 0th hour and ending at the 5th hour, results in finding an accumulated SUM of: 0 + 1 + 2 + 3 + 4 + 5 => 15.
Moving to window time '5', you find that an offset of '-2' lands at the same starting index of '0', even though window time '5' is an operational time interval, because when incorporating with offsets, you do not include the status of the current window. This consequently leads you to the same accumulated SUM: 0 + 1 + 2 + 3 + 4 + 5 => 15.
We can extrapolate this process out to find that the resulting timeseries produces data that looks like: [0.0, 0.0, 0.0, 0.0, 15.0, 15.0, 18.0, 35.0, 35.0, ...].
Negative offset flavor #2
The second flavor of the negative offset works to help calculate the aggregation from the last X intervals to the current time window. This expression would look like: operationalWindow('SUM', ServiceCount, InFlight, -2)', where the operationalSpan is either ignored or left null. Note: operationalSpan can only be left null if the offset is negative as the concept doesn't make sense for zero or positive offsets.
In this case, the offset behaves in the same way as in flavor #1 but the span is absolute (meaning not operational) and changes to fit the time range between the offset and the current time window.
So again, starting at window time '4', by jumping an offset of '-2' or two operational hours in the past, you land on the 0th hour and by aggregating all data starting from the offset, at the 0th hour, to the current window, hour 4, you find an accumulated SUM of: 0 + 1 + 2 + 3 => 6.
Then moving to window time '5', you find that an offset of '-2' lands you at the same starting index of '0' but since the current time window has now shifted to time window '5', you are also aggregating over the sum over time window '4' which leads us to the accumulated SUM: 0 + 1 + 2 + 3 + 4 => 10.
It is possible to extrapolate this process out to find that the resulting timeseries produces data that looks like: [0.0, 0.0, 0.0, 0.0, 6.0, 10.0, 12.0, 11.0, 18.0, ...].