Cube builder
Data Cube
To set up a data cube, you can override the ADataCubeConfigurer
class.
Query cube
To set up a query cube, you can override the AQueryCubeConfigurer
class.
Methods to override
ADataCubeConfigurer constructor
The constructor of the class gets the dimensions and the aggregate provider configuration of the cube.
AggregateProviderConfig mdConfiguration = builder -> builder
.withAggregateProvider()
.bitmap()
.withModuloPartitioning(StoreFieldConstants.RISK_FACTOR, NUM_HASH_PARTITIONS)
.withAggregatesCache().withSize(aggregateCacheProperties.getSize());
DimensionsAdder aDimension = builder -> builder
.withDimension(CURRENCIES_DIM)
.withHierarchy(CURRENCY_HIERARCHY)
.withLevel(CCY_LVL);
HierarchyBuilderConsumer aHierarchy = hierarchyBuilder ->
hierarchyBuilder.toDimension(MARKET_DATA_DIMENSION, builder ->
builder
.withHierarchy(MARKET_DATA_SETS_HIERARCHY)
.slicing()
.fromStore(MARKET_DATA_SETS_STORE_NAME)
.withLevel(MARKET_DATA_SET_LEVEL)
.withFieldName(MARKET_DATA_SET));
List<?> dimensions = List.of(aDimension, aHierarchy);
var cube = new ADataCubeConfigurer(mdConfiguration, dimensions) {
// ...
};
AQueryCubeConfigurer constructor
Parameters:
QueryCubeAggregateProviderConfig configuration
The injection of the bean that contains the performance-related elements of the cube cache.boolean appMeasureGroup
Enables or disables the application measure groups. If enabled, all measures and hierarchies from a data node are grouped in a measure group (whose name is the application id of the DATA node they come from).boolean appMeasureName
Enables or disables the application measure names. If set to true, measures names coming from the data cubes are suffixed in the query cube with the application id of the DATA cube they come from.
copperMeasures
Used to define the Copper Measures of the cube:
@Override public void copperMeasures(ICopperContext context) {
Copper.sum("v0").as("v0").publish(context);
}
getKpis
Sets the KPIs of the cube:
@Override public Collection<IKpiDescription> getKpis() {
IKpiDescription kpi = StartBuilding.kpi()
.withName("VAR 99% Monitoring")
.withValue(new KpiValueDescription("[Measures].[Exception 99 Count]"))
.withGoal(new KpiGoalDescription("12"))
.withStatus(new KpiStatusDescription(
"""
Case
When IsEmpty(KpiGoal("VAR 99% Monitoring"))
Then NULL
When KpiValue("VAR 99% Monitoring") > KpiGoal("VAR 99% Monitoring")
Then -1
Else 1
End""",
"Shapes"))
.build();
return List.of(kpi);
}
schemaSelectionDescription
Defines the selection of the cube.
@Override public ISelectionDescription schemaSelectionDescription(IDatastoreSchemaDescription datastoreSchemaDescription) {
return StartBuilding.selection(datastoreDescription.asDatabaseSchema())
.fromBaseStore(BASE_STORE_NAME)
.withAllFields()
.build();
}
sharedContextValues
Defines the context values set by default in the cube.
@Override public <T> ICanBuildCommonCubeDescription<T> sharedContextValues(ICanBuildCommonCubeDescription<T> builder) {
builder = builder.withSharedContextValue(new VaRConfidenceLevel(99));
return builder;
}
measures
Defines measures in the old way. This is deprecated and should be replaced by Copper measures.
@Override
public IHasAtLeastOneMeasure measures(ICanStartBuildingMeasures builder) {
for (IMeasureBuilder measureBuilder : measureBuilders) {
for (IPostProcessorDescription ppd : measureBuilder.getPostProcessors()) {
builder = builder.withPostProcessor(ppd);
}
}
return (IHasAtLeastOneMeasure) builder;
}
mdxContext
Sets some specifics related to the MDX engine for this cube:
@Override
public IMdxContext mdxContext(ICanStartBuildingMdxContext.IMdxContextBuilder<IMdxContext> mdxBuilder) {
return mdxBuilder
.withDefaultMember()
.onHierarchy("[PnL].[Types]")
.withMemberPath("[Type].[Actual PL Attributed]")
.build();
}
cubeName
Sets the cube name
@Override
public String cubeName() {
return "Sensitivity Cube";
}
schemaName
Sets the schema name
@Override
public String schemaName() {
return "SensiSchema";
}
applicationId
Sets the application id, used to declare a data cube type on the cluster:
@Override public String applicationId() {
return "Sensi";
}
getDistributedApps
On the query cube, you need to register all the cube application ids with their distribution key:
@Override private Map<String, String[]> getDistributedApps() {
String[] DISTRIBUTION_FIELD = new String[] { AS_OF_DATE };
Map<String, String[]> applications = new HashMap<>();
applications.put("Sensi", DISTRIBUTION_FIELD);
applications.put("VaR", DISTRIBUTION_FIELD);
return applications;
}
Methods to expose
To grab all cube setups and create an Atoti application, you need to expose some beans from the cube configurer.
cubeName
To create the cubes catalog, you must expose all the cube names as beans:
@Bean("sensiCubeName")
@Qualifier("Risk_CubeName")
@Order(20)
@Override
public String cubeName() {
return CUBE_NAME;
}
buildCube
And finally the most important bean to expose, the CubeBuilderFunction
that provides the lambda used to construct the cube itself:
@Bean("buildSensiCube")
@Qualifier("Cube")
@Override
public CubeBuilderFunction buildCube(@Qualifier(SP_QUALIFIER__DATA_CUBE_MESSENGER_DEFINITION) IMessengerDefinition dataCubeMessengerDefinition) {
return super.buildCube(dataCubeMessengerDefinition);
}
Additional Spring beans needed to build an application
The Catalog
The catalog contains all the cube names, it will grab all the cubeName beans to be constructed:
@Bean
@Qualifier("Catalog")
@Order(10)
public Function<IActivePivotManagerDescriptionBuilder, IActivePivotManagerDescriptionBuilder> buildRiskCatalog(@Qualifier("Risk_CubeName") List<String> cubeNames) {
return builder -> builder.withCatalog("MarketRisk").containingCubes(cubeNames.toArray(String[]::new));
}
The application builder
Here is the configuration bean that will grab all the cubes and set up an application:
@Configuration
public class MarketRiskManagerConfig implements IDatastoreSchemaDescriptionConfig, IActivePivotManagerDescriptionConfig {
protected final List<Function<IActivePivotManagerDescriptionBuilder, IActivePivotManagerDescriptionBuilder>> catalogs;
protected final List<CubeBuilderFunction> cubes;
protected final IDatastoreConfigurator datastoreConfigurator;
protected final Collection<Collection<Set<StoreField>>> extraSameDictionaryDescriptions;
public static final String MANAGER_NAME = "MarketRiskManager";
public MarketRiskManagerConfig(
@Qualifier("Catalog") List<Function<IActivePivotManagerDescriptionBuilder, IActivePivotManagerDescriptionBuilder>> catalogs,
@Qualifier("Cube") List<CubeBuilderFunction> cubes,
IDatastoreConfigurator datastoreConfigurator,
@Qualifier("sameDictionaryDescription") @Autowired(required = false) Collection<Collection<Set<StoreField>>> extraSameDictionaryDescriptions) {
this.catalogs = catalogs;
this.cubes = cubes;
this.datastoreConfigurator = datastoreConfigurator;
this.extraSameDictionaryDescriptions = extraSameDictionaryDescriptions;
}
@Override
@Bean
public IActivePivotManagerDescription managerDescription() {
IActivePivotManagerDescriptionBuilder builder = StartBuilding.managerDescription(MANAGER_NAME);
builder = catalogs.stream().reduce((a, b) -> b1 -> b.apply(a.apply(b1))).orElse(o -> o).apply(builder);
BuildableActivePivotSchemaDescriptionBuilder builder2 = cubes
.stream()
.reduce((a, b) -> (b1, d1) -> a.apply(b.apply(b1, d1), d1))
.orElseThrow(() -> new ActiveViamRuntimeException("No cube"))
.apply(builder, datastoreSchemaDescription());
return builder2.build();
}
@Override
@Bean
public IDatastoreSchemaDescription datastoreSchemaDescription() {
var datastoreSchemaDescription = datastoreConfigurator.buildSchemaDescription();
if(extraSameDictionaryDescriptions != null) {
var sameDictionaryDescriptions = new ArrayList<>(datastoreSchemaDescription.getDictionaryGroups());
extraSameDictionaryDescriptions.forEach(sameDictionaryDescriptions::addAll);
return new DatastoreSchemaDescription(datastoreSchemaDescription.getStoreDescriptions(), datastoreSchemaDescription.getReferenceDescriptions(), sameDictionaryDescriptions);
} else {
return datastoreSchemaDescription;
}
}
}