Getting started
This section provides guidance on developing with the Limits Module.
Provided is a minimalist ActivePivot project built with Spring Boot for you to edit, customize, and use as a base for your ActivePivot projects.
Details
This project aims to be an example of how to run the Limits Module with an ActivePivot Spring Boot application.
This project is a starting point for your own projects and implementations. You should be able to take this, customize it, and get a cube up and running in a few minutes.
📦 Installation
Requirements
- Java 11
- Maven 3
- ActivePivot (AP5.10) JAR files
- Running the application requires a license for the ActivePivot software.
Distribution
Limits backend source
To access the Limits backend source zip folder, click here.
Unzip this repository and run mvn clean install
.
This will generate a JAR file, which can be run using standard java commands.
Limits UI
- The Limits Module contains customized UI widgets
- Download the Limits Module from https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/1.0.1/limits-ui-source-1.0.1.zip
- Update public/limits-env.js
- Run
yarn install
- Run
yarn start
onhttp://localhost:3000
- Run
yarn build
for building a production-deployable package under thebuild
folder.
💻 Usage
The Limits Module can be integrated with any ActivePivot instance with the same AP version. For more information, see How to Integrate Limits to Atoti+.
As Of Date
The file as_of_date.csv sets the asOfDate for the limits application. This asOfDate is used for evaluating limits against connected accelerators.
Limit definitions
The files limits_approve_frtb.csv and limits_approve_mra.csv load the LimitsDefinition store, and can be found in src/test/resources/data-samples/data/
. Limit
definitions which have the same Name, CubeName, and ServerName fields create a single KPI on a connected server via REST calls.
For more information on the Limits approve files, see Limits approve.
note
Currently, limits_approve_mra.csv is being ignored because the ETL will skip un-configured accelerators. To load MRA limits, modify acc.url.map prop
in src/main/resources/properties/limits.properties
to include MRA. (
Example: {'MRA': 'http://localhost:10010/risk-activepivot/pivot/rest/v5/cube', 'FRTB': 'http://localhost:8080/frtb-starter/pivot/rest/v5/cube'}
)
AlertTasks and Alert Definitions store
AlertTasks are created for each limit definition in the LimitsDefinition store, which evaluates whether a limit is in breach or warning state. The
PollingFrequency field of a limit definition determines how often an AlertTask is run. When limits are in breach or warning status the AlertTask writes to a file named alert.csv. You can find this file in today’s date folder inside the directory src/test/resources/data-damples/data/alert
. The files generated here will populate the AlertsDefinition store via a listening topic.
Limit workflow
In the resources/processes folder, the following Activiti workflow bpmn files can be found out of box.
- limit-process-four-eyes.bpmn
- limit-process-six-eyes.bpmn
- limit-process-straight-through.bpmn
- limit-process-exception.bpmn
Limit Scopes
Limit definition Scope matching
A Limit Scope is a list of Level Name to Level Value pairs. The Scope represents one or many locations in the Cube where the Limit should be applied. For example, for a Limit to apply when “Trade1” is expressed for the “Trade” dimension, the Value/Pair “Trade=Trade1” can be defined as the Limit’s Scope.
A Scope needs to be specific enough so that its definition only matches one Member in the Cube, to avoid Ambiguous Scopes. The Scope can consist of multiple Level definitions within the format: key=value|key=value|key=value
. Each individual Scope is separated by a pipe ‘|’ character.
A Scope is broken up into two main components:
- Scope Key: Specifies a Level in the Cube. Can be provided in one of 3 ways:
LevelName
- (Minimum required): Only specifies the Level Name.LevelName@HierarchyName
- (Optional): Specifies the Level in a specific Hierarchy.LevelName@HierarchyName@DimensionName
- (Optional): Specifies the Level in a specific Hierarchy in a specific Dimension.
- Scope Value: Member within the provided Level to apply the Limit.
note
If a level could not be provided for a “LevelName@HierarchyName” or “LevelName@HierarchyName@DimensionName” then we will invert the ordering and try to find the level again. If we are able to find the inverse level description then we will log a warning notifying that the input data may be in the incorrect format.
A Scope can only be defined once for each Level of the Cube. To define a Limit for multiple Level Members of one Cube Level, you need to define multiple Limit Definitions, each with a different Level Member value in the scope.
A Scope can consist of both explicit and wildcard Scopes.
Explicit Scopes
An explicit Scope value is one where the Cube Level and Level Member are explicitly defined.
For example:
ID=1
Multiple Explicit Scopes
A Scope can have multiple Explicit values.
For Example:
Vertex=1d|Vertex=1m|Vertex=1w
Wildcard Scopes
A Scope’s Level Value can also be applied to all Level Members of a given Cube Level. This is done by specifying a Scope where the Cube Level Member is a ("*") wildcard. This will match all Members of the given Cube Level. An example of a wildcard scope is defined below:
ID=*
«!–#### Parent Child Scopes
A Parent-Child scope is a scope defined on Parent-Child hierarchy, which is a multi-level hierarchy where a parent/child relationship exists between the hierarchy’s levels. For example, the BookHierarchy, in FRTB, hierarchy consists of levels Level 1, Level 2, Level 3,…, Level 15 and each level has a parent/child relationship with the next level (Level 1 is a parent to Level 2, etc.).
In order to create valid Parent-Child scope’s via initial CSV loading, the property parent-child.levels
must be set, declaring all Parent-Child hierarchies. The format of the property value is:
An example:
parent-child.levels=FRTB@StandardisedApproachCube=BookHierarchy@Organization
—>
All Member Scopes
A Scope’s Level Value can also be applied to the AllMember Level of a given Cube Level. This is done by specifying a Scope where the Cube Level Member is a (“AllMember”). This will match the Total / AllMember of the given Cube Level. An example of an AllMember scope is defined below:
Book=AllMember
Ambiguous Scopes
A Scope can be ambiguous if the Level or Level Member specified exists in multiple Hierarchies.
Ambiguous Level Name
Assuming we have the following Cube Structure:
Dimension | Hierarchy | Levels |
---|---|---|
Calendar | Days | Year, Month, Day |
Calendar | Leap Years | Year |
If we specify a Scope Year=2022
then Limits will throw an exception as Year
is ambiguous and relates to two Levels in the Cube Year
of the Days
Hierarchy and Year
of the Leap Years
Hierarchy. To fix this, we will need to specify that we want the year
of the Leap Years
Hierarchy: Year@Leap Years=2022
.
Ambiguous Level Path
A Level Member is Ambiguous if it’s a part of a Multi-Level Hierarchy and there are multiple paths through the Hierarchies Levels to get to this specific Level Member. This can be explained easier with an example:
Assuming we have the following Cube Structure:
Dimension | Hierarchy | Levels |
---|---|---|
Calendar | Days | Year, Month, Day |
With the below data for the Levels of the Days
Hierarchy.
Year | Month | Day | Number Of Days |
---|---|---|---|
2021 | |||
January | 31 | ||
First | 1 | ||
Second | 1 | ||
February | 28 | ||
First | 1 | ||
Second | 1 | ||
2022 | 366 | ||
January | 31 | ||
First | 1 | ||
Second | 1 | ||
February | 29 | ||
First | 1 | ||
Second | 1 | ||
Third | 1 |
If we specify a scope Month=February
we either get a warning or an exception, depending on the value of scope.force-unambiguous-level-paths, as the Level Member does not have an absolute path back to the root. What this means is that there are two ways to get to the month February within the Days Hierarchy: [2021/February
, 2022/February
]. To fix this, we need to specify the Levels back to the root. Our scope will now look like: Month=February|Year=2022
.
If we specify a scope Day=Third
, there is no ambiguity, as there’s only one path to the Day Third: 2022/February/Third
.
If we specify a scope on Day=Third
, we can optionally store the values for Month
and Year
if scope.autofill-unambiguous-level-paths is enabled. This results in an internal Scope of: Day=Third|Month=February|Year=2022
. This way, if more data is loaded in later, the Day=Third
could become ambiguous, especially if a value Third
is loaded for one of the other Months.
With the handling of ambiguous paths, we have the following properties to change the default handling of ambiguous scopes:
scope.force-unambiguous-level-paths
This property forces that a level be Unambiguous at load time. This means that for the provided Level Member there is only one path back to the Root Level Member. For instance, the scope Month=February
is ambiguous since there are two paths to February. If we specify Month=January|Year=2021
then the scope is no longer ambiguous, as there is no other path back to the root.February.
Enabling this property will not allow any data to be loaded if more than one path exists back to the root.
Disabling this property will allow our scope of Month=February
. Our Limit in this case will apply to all Years.
note
The path is data dependent: new data can cause an unambiguous Level Member to become ambiguous later on.
scope.autofill-unambiguous-level-paths
This property allows a Limit’s Scope to be modified at load time. IFF the Level Member provided of a Scope is unambiguous, we add all un-specified Level Members to the Scope as well. This will lock this Limit’s Scope location so if new data comes in, we won’t have to worry about the Scope becoming ambiguous and apply to other locations.
For example, if we specify the scope Day=Third
, there is only one path back to the root: 2022/February/Third
. So we will add the these values to our scope. In the end, our scope will be: Year=2022|Month=February|Day=Third
. In this case if a Third
day were to be loaded for another month, our scope will still only apply to the 2022/February/Third
location as it did when we initially loaded the limit.
note
If autofill is turned on and multiple Paths are found for a Level Member, an exception will be thrown as a Scope can only be on one path of a Multi-Level Hierarchy.
Limit lookup
Because this can potentially cause multiple Limit Definitions to be applied to any location in the cube, Limit definition collisions are resolved by the following logic:
We take the Limit Definition that has:
- A higher precedence
- Matches a location with more explicit scope matches.
- Matches a location with more wildcard scope matches.
- Has a lesser value.
Other
note
If running as a JAR file, the limits_approve.csv file may not be found, and you will need to explicitly point to it.
- ActiveUI, ActiveViam’s user interface for exploring the cube, will be available from
http://localhost:9090/ui
The default security credentials are admin:admin
, but can be modified in the SecurityConfig
class (we use Spring Security).