Inter-cube Feeders

In my previous month’s article on “Managing the Art of Feeders”, we reviewed the concept of using Skipcheck and Feeder functionality in standard TM1 rules. In this month’s article, we will discuss further enhancing a developer’s capability around writing rules within TM1 and review the concept of inter-cube feeders. While much of the functionality and capability found within TM1 rules is necessary to provide the desired end user result set, that does not mean that a developer should simple assume that all functionality is created equal. Inter-cube feeders, while often necessary, can have a significant impact on overall performance which should be taken into consideration before inclusion in a rule.

The Challenge

One of the main reasons for the performance impact is around the fact that not all cubes are created with the same level of granularity. This can dictate the need to feed a consolidation level element to your hierarchy. When you are feeding to a consolidation level, such as “Forecast Years”, you’re actually creating multiple feeders equal to the amount of Children under the Parent. In the case of a year level this could include quarters, months, weeks and days. So for example, if you are grabbing salary and bonus % information to calculate a yearly bonus or a FICA amount from an Employee cube that does not contain a time dimension and then applying those values in a Headcount cube that does have “Quarter”, “Month” or “Forecast Years” dimension you are going to run into this issue of non-matching dimensions. An inter-cube feeder that contained matching dimensions would appear simpler to the following:

[‘Empl_Statistics’] => DB(‘Headcount’, !Forecast Years, !Months, !Version, !Cost Center, !Location, !Employee, !Emp_Data);

The Feeder statement above assumes the Empl_Statistics cube has a Time Dimension

Source Cube

 

However, when there is no Time dimension in our source cube and we need to feed “Forecast Years”, “Months” etc. we are essentially writing the following Feeders:

[‘Empl_Statistics’] =>

DB(‘Headcount’, ‘2013’, ‘Jan’, !Version, !Cost Center, !Location, !Employee, !Emp_Data),

DB(‘Headcount’, ‘2013’, ‘Feb’, !Version, !Cost Center, !Location, !Employee, !Emp_Data),

DB(‘Headcount’, ‘2013’, ‘Mar’, !Version, !Cost Center, !Location, !Employee, !Emp_Data), thru Dec

DB(‘Headcount’, ‘2014’, ‘Jan’, !Version, !Cost Center, !Location, !Employee, ! Emp_Data), thru Dec

DB(‘Headcount’, ‘2015’, ‘Jan’, !Version, !Cost Center, !Location, !Employee, ! Emp_Data), thru Dec

DB(‘Headcount’, ‘2016’, ‘Jan’, !Version, !Cost Center, !Location, !Employee, ! Emp_Data, thru Dec

DB(‘Headcount’, ‘2017’, ‘Jan’, !Version, !Cost Center, !Location, !Employee, ! Emp_Data) thru Dec and so on;

Target Cube

 

 

As you can see one Feeder becomes sixty or however many Forecast Years/Months you are using. This is where performance is compromised.

The Solution

This is where carefully considering the process of developing feeders comes into play. If we simply break the feeder into two parts, the first feeder located in the “Employee Statistics” cube and feed the specific element “FTE” inside the “Emp_Data” dimension of the Headcount cube and then create a Feeder inside the “Headcount” cube to feed all of the leaf level elements in the “Emp_Data” dimension we would have had to have fed from the Employee Statistics cube we have effectively created a “workaround”, and a solution to a very specific performance issue. The Feeder I am describing is located below.

[‘Statistics_Measures’] => DB(‘Headcount’, ‘Forecast Years’, ‘Months’, !Version, !Cost Center, !Location, !Employee, ‘FTE’);

Then in the Feeder below we would be able to use that newly-fed “‘FTE’” element in the “Headcount” cube to feed all of the Elements in the Emp_Data Dimension impacted by the Rule in the Headcount cube for which we otherwise would have had to have written inter-cube Feeders.

[‘FTE’] => [‘Annual Salary’], [‘Bonus’], [‘Bonus %’], [‘Medicare’], [‘Social Security’]

There will obviously be some trial and error with this particular scenario especially when you are new to TM-1 because of the complexity it presents but with some time with the tool you will be able to overcome these more enigmatic challenges.

Conclusion

While it is not possible to completely eliminate the complexity that comes with having to use feeders whether they are basic or Inter-cube, it is important to always consider the impact of a feeder on overall performance before coding begins. There are often more efficient ways to attack a singular problem. This is the real danger of an application as robust as TM1, just because the capability exists to code a rule in a certain method, does not mean that you should not investigate alternatives.