Cube Configuration
Introduction
To organize and structure data, Atoti is using OLAP cubes with hierarchies and measures.
- The hierarchies defined the structure of the data.
- The analysis is done accessing measures for different locations.
If the application is complex and cover several use cases, it is possible to define several cubes in the same application. We organize them using catalogs and schemas:
- A catalog is a collection of cubes.
- A schema is a collection of cubes that have the same selection on the underlying database. It means that the cubes inside a same schema are based on the same data.
The manager will orchestrate catalogs and schemas. This is the highest entity.
All these objects can be described using the StartBuilding fluent builder.
Create selection, managers, catalogs and schemas
Create a selection
To create a selection, use StartBuilding.selection():
fromBaseStore("storeName")defines the base storewithAllReachableFields()adds all the fields reachable from the base store via the references in the database.withField("fieldName")adds one field to the selectionwithAlias("fieldName", "alias")defines a new name for a field
final ISelectionDescription selection =
StartBuilding.selection(schemaDescription)
.fromBaseStore("store")
.withAllReachableFields()
.build();
Adding fields individually:
final ISelectionDescription fieldByFieldSelection =
StartBuilding.selection()
.fromBaseStore("store")
.withField("field1")
.withField("field2")
.build();
Create managers, catalogs and schemas
To create a selection, use StartBuilding.manager():
withSchema("schemaName")defines a schema. The name is optional if there is only one schema. The default name is " Schema".withSelection(selection)adds the selection created earlierwithCube(cubeDescription)adds a cube description. How to create a cube description is described below.withDistributedCube(cubeDescription)adds a distributed cube description.withCatalog("catalogName)groups the cubes into catalogs. This is optional if there is only one catalog. The default name of catalog is "Catalog".
Here is a simple example:
final IActivePivotManagerDescription desc =
StartBuilding.managerDescription()
.withSchema()
.withSelection(selection)
.withCube("Cube", b -> b.withSingleLevelDimension("field"))
.build();
Here is a more complex example:
final IActivePivotManagerDescription desc =
StartBuilding.managerDescription()
.withSchema("A")
.withSelection(selection)
.withCube("C", b -> b.withSingleLevelDimension("f"))
.withSchema("B")
.withSelection(StartBuilding.selection().fromBaseStore("a").withField("f").build())
.withCube("C2", b -> b.withSingleLevelDimension("f"))
.withCatalog("C")
.containingCubes("C")
.withCatalog("Main")
.containingAllCubes()
.build();
It is possible to give the manager a name to be able to create several. The default name is "Manager".
The catalogs names are displayed in the UI (as opposed to the managers names and schemas names).
Cube Configuration
To create a cube, use StartBuilding.cube("cubeName").
Create a minimal cube
The minimal cube only has a single level (so a single hierarchy and a single dimension) and only the native measures ( the contributors count and a timestamp).
final IActivePivotInstanceDescription desc =
StartBuilding.cube().withName("Cube").withSingleLevelDimension("level").build();
Add measures and dimensions
To add dimensions, hierarchies and levels please see the dedicated articles.
To add measures, the preferred way is Copper.
To add simple aggregated measures, use withAggregatedMeasure():
- choose a common aggregation function with
sum("fieldName"),min("fieldName"),max("fieldName"),avg("fieldName") - call the aggregation function plugin key otherwise with
withAggregateFunctionFunction(pluginKey) - optional: choose a folder to visually organize the measure in with
withinFolder("folderName") - optional: choose a formatter with
withFormatter("formatter")
Here is an example that defines several measures:
final Function<ICanStartBuildingMeasures, IHasAtLeastOneMeasure> measures =
b ->
b.withContributorsCount()
.withFormatter("INT[#,###]")
.withAggregatedMeasure()
.sum("pnl")
.withinFolder("pnl")
.withFormatter("DOUBLE[#,###.00;-#,###.00]")
.withAggregatedMeasure()
.sum("delta")
.withinFolder("sensitivities")
.withFormatter("DOUBLE[#,###.00;-#,###.00]");
StartBuilding.cube()
.withName("MyCube")
.withMeasures(measures)
.withDimensions(dimensions)
.build();
Optional cube configurations
Configure the aggregate provider
To add an aggregate provider, please see the dedicated article.
Configure the aggregate cache
The queries are run using an aggregate cache to avoid useless recomputation. To optimize the memory, it is possible to choose the aggregate cache size and which measures should be cached.
Use withAggregateCache to configure the aggregate cache:
withSize()defines the cache sizecachingOnlyMeasures("measure1", "measure2")lists the measures to keep in the cache
StartBuilding.cube()
.withName("MyCube")
.withMeasures(measures)
.withDimensions(dimensions)
.withAggregateProvider()
.jit()
.withAggregatesCache()
.withSize(10_000)
.cachingOnlyMeasures("contributors.COUNT", "pnl.SUM")
.build();
Configure the shared context values
The cube description can also define context values for all queries of all users.
Use withSharedContextValue to define shared context value:
StartBuilding.cube()
.withName("MyCube")
.withMeasures(measures)
.withDimensions(dimensions)
.withSharedContextValue(
new DrillthroughProperties(
new CustomComparator<>(List.of("Desk", "Currency"), null),
List.of("BookId", "City"),
List.of(
new CalculatedDrillthroughColumnDescription(
"DoubleAdder", "delta + gamma", "delta,gamma")),
List.of(
new CalculatedDrillthroughColumnSetDescription(
"PnlCurrencyColumnSet",
Immutable.map("prefix", "pnl in", "currencies", "EUR,USD,GBP,JPY,CHF,ZAR")
.toProperties()))))
.withSharedContextValue(new MdxContext())
.build();
Add a global fact filter
The cube retrieves its data from the database using the selection. It is possible to filter some of the data using a fact filter.
The filter is applied when feeding the cube, on the facts in the selection, before any queries happening.
The cube retrieves data from the database based on the defined selection. A fact filter can be applied to limit the facts available to the cube. This filter ensures that all queries and updates on the cube respect the specified condition. Any operation performed on the cube, including queries and updates, is constrained by the fact filter. To create a fact filter, use withFactFilter(condition) and define the filtering condition.
StartBuilding.cube()
.withName("MyCube")
.withMeasures(measures)
.withDimensions(dimensions)
.withFactFilter(FactFilterConditions.eq("field", "value"))
.build();