Level Configuration
This guide aims at providing the basic configuration tips to start defining levels with the fluent builder.
Introduction
Hierarchies categorize data into levels for aggregation and visualization. For more info about hierarchies, see here.
- The levels in a hierarchy are organized with parent-child relationships.
- All non-slicing hierarchies have a parent level, called "AllMember", to aggregate data across all members of all levels. It is created and configured automatically.
- The level is often based on a column of the database from which they inherit a data type, a formatter and a comparator.
Basic configuration
For a hierarchy, use:
withDimension("dimensionName")
to define the dimensionwithHierarchy("hierarchy)
to define a hierarchywithLevel("levelName")
to define the levels.
builder.withDimension("Time").withHierarchy("Time").withLevel("year").withLevel("month");
Here the order is important : the level "year" is defined first so it will be the parent of the level "month".
Several shortcuts are provided by the builder.
For example, define a dimension, with one hierarchy and one level, all with the same name, with
withSingleLevelDimension("dimensionName")
:
StartBuilding.cube()
.withName("Cube")
.withDimensions(builder -> builder.withSingleLevelDimension("Currency"));
The level is based on the first reachable field, with the same name, in the database. The level inherits the data type and other properties from the field. Specify a field name after the level name to:
- Create a level with a different name to the selection field
- Create a level that is based on a specific selection field (i.e. not the first reachable field with the same name as the level)
builder.withDimension("Trader").withHierarchy("Trader").withLevel("Trader", "Trader_id");
Defining the time levels
Level types
There are mainly three level types:
ALL
the type of the "AllMember" level that exists as the first level of all non-slicing hierarchiesTIME
for time levels (with specific subtypes for the different time units)REGULAR
for the other levels (it is the type defined by default).
The level type is different from the data type of the selection field the level is based on. The data type is the type of the members of the level: double, string, date...
Use withLevelType(ILevelInfo.LevelType.TIME)
to define the type of the levels representing time so that they are
correctly handled by time measures (for example, finding the first month of a quarter).
builder
.withDimension("Time")
.withType(IDimension.DimensionType.TIME)
.withHierarchyOfSameName()
.withLevel("Time")
.withType(ILevelInfo.LevelType.TIME);
Formatter
By default, each data type has a formatter to define how to display the level members:
- add a comma to group thousands in numbers
- format dates
Simple formatter can be used with their string representation:
builder
.withDimension("Time")
.withType(IDimension.DimensionType.TIME)
.withHierarchyOfSameName()
.withLevel("year")
.withFormatter("DATE[MM-DD-YY]");
To define a custom formatter, see this page.
Ordering level members
By default, members of a hierarchy are ordered:
- Alphanumerically for data with type string
- Chronologically for dates
The order of the level members affects
- the order in which the members are displayed on the dashboard.
- the level member selected for some commutations (such as lag and lead measures).
First objects
To fix the first objects so they always appear on top, use withFirstObjects
:
builder.withSingleLevelDimension("Currency").withFirstObjects("USD", "EUR", "GBP");
Custom comparator
To define a comparator, use withComparator("myComparatorKey)
and define your own comparator or use one of our
implementation.
The comparator should be an implementation of IComparator<Object>
which wraps a java.util.Comparator
into a plugin
value for easier configuration.
Define your custom comparator, in a separate class:
@AtotiExtendedPluginValue(key = MyComparator.PLUGIN_KEY, intf = IComparator.class)
public static class MyComparator implements IComparator<Object> {
public static final String PLUGIN_KEY = "MyComparator";
@Override
public String getType() {
return PLUGIN_KEY;
}
@Override
public int compare(Object o1, Object o2) {
// define your compare function here
return 0;
}
}
Use its plugin key in the fluent builder:
builder.withSingleLevelDimension("Trades").withComparator(MyComparator.PLUGIN_KEY);
Member properties
Each member can have additional properties. They are not used to aggregate data but can be displayed in the UI and used to look up a member (like an alias for example). For more details, see the dedicated page