Skip to main content

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 dimension
  • withHierarchy("hierarchy) to define a hierarchy
  • withLevel("levelName") to define the levels.

builder.withDimension("Time").withHierarchy("Time").withLevel("year").withLevel("month");

note

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 hierarchies
  • TIME for time levels (with specific subtypes for the different time units)
  • REGULAR for the other levels (it is the type defined by default).
note

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