Table of Contents:
Why Migrate?
Keeping track of your IT spending can be challenging. Designing and implementing a cost management model with aggregations, dataflows, and information gathering is a major task.
The Ardoq IT Cost Management (ITCM) use case, which comes preconfigured, offers quick start-up and fast results.
To maximize realized value, Ardoq continually develops and refines its best practices. As a result of our feedback and iterative design process, we have extended the ITCM metamodel to further meet the needs of organizations.
The purpose of this document is to explain the differences between v1 and v2 of the ITCM metamodel and how you can migrate from v1 to v2.
Benefits of Migrating to v2:
Cost showbacks can be shown to departments and teams with the inclusion of Organizational Unit cost fields.
Before you begin:
It is assumed that you have the IT Cost Management Use Case deployed on your Ardoq instance.
Version 2 migration is optional, but recommended
There is no automated migration solution available at the moment, so manual migration is necessary
You have notified all parties who may be affected by this change
You need a team member in your organization who can modify Ardoq's configuration (metamodels, fields, broadcasts, and reports). Ardoq admins are typically responsible for this.
1. Changes to the Metamodel
In the screenshots below you can see how the two metamodels compare with each other. Fields that need to be modified are highlighted in the new metamodel.
Old
New
2. Changes to fields
Below you will find a list of field changes (workspaces & references) that need to be made, as well as links to the corresponding fields with gremlin code changes.
Field | Workspace &
Reference Types | New
Removed
Changed | Replacement | Gremlin code |
Total Consumed Cost | All workspace types | Removed | Total Attributed Cost | |
Total Cost | All workspaces types | Changed. New gremlin | - | |
Total Consumption Percentage |
| Removed | Total Attributed Percentage | |
Cost Consumption Percent Data Quality |
| Removed | Cost Attribution Percent Data Quality | |
Cost Consumption | All reference types | Removed | Cost Type Attribution |
|
Cost Consumption Percentage | All references types | Removed | Cost Attribution Percentage |
|
Total Attributed Percentage |
| New |
| |
Cost Attribution Percent Data Quality |
| New |
| |
Cost Type Attribution |
| New |
|
|
Cost Attribution Percentage |
| New |
|
|
Total Attributed Cost |
| New |
| |
Budgeted CAPEX | Organization Workspace | New |
|
|
Budgeted OPEX | Organization Workspace | New |
|
|
Total Budgeted Cost | Organization Workspace | New |
|
3. Changes to the presentation
ITCM - IT Cost Management Presentation needs to include v2 fields where v1 fields are shown (fields containing "Consumes"/"Consumption"/"Consumed"). As shown in the table above, they have been replaced by corresponding v2 fields.
4. Changes to reports
Green highlights indicate new reports that need to be configured. Each new report should be configured according to the screenshots below. For every Gremlin Graph Search report, the Gremlin code is provided.
ITCM DQ - Over allocated Org Units
ITCM DQ - Cost Type Attribution is Activated
fieldName = 'cost_type_attribution'
referenceTypesWithField =
g.E().
has(fieldName).
project('label', 'rootWorkspace').
by(label()).
by('rootWorkspace').
dedup().
fold().
next()
hasTypeWithField = {
referenceTypesWithField.any{ type ->
it.get().label() == type.label &&
it.get().value('rootWorkspace') == type.rootWorkspace
}
}
g.E().
filter(hasTypeWithField).
filter{ it.get().property(fieldName).orElse([]).size > 0 }/*.
count()*/
ITCM DQ - Org Units without Cost
ITCM - Showback
def toUSD = {
amount = String.format("%,.0f", (Double) it.get());
return "\$"+amount;
}
g.V().hasLabel('Organizational Unit').filter(__.out('Consumes').hasLabel('Application').values('name')).
project('name', 'Consumption Cost', 'Consuming Applications').
by('name').
by(
__.out('Consumes').hasLabel('Application').
as('totalCost', 'numberOfConsumesApplications').
math('totalCost / numberOfConsumesApplications').
by(coalesce(values('total_cost'), constant(0))).
by(__.in('Consumes').hasLabel('Organizational Unit').count()).
sum().map({ it.get().toFloat() }).map(toUSD)
).
by(__.out('Consumes').hasLabel('Application').values('name').fold().dedup())
ITCM - Total Cost of Organizational Units
g.V().hasLabel('Organizational Unit').project('name', 'Total Cost').
by('name').
by(values('total_direct_cost', 'total_attributed_cost').sum().map{ (it.get() as Double).round(0) })
ITCM - Attributed Cost of Organization Units
g.V().hasLabel('Organizational Unit').values('total_attributed_cost').sum() |
5. Changes to Gremlin Graph Searches
To see what needs to be changed, please refer to the field table
New versions:
Total Attributed Cost
This contains the Gremlin Code that aggregates the underlying components' costs to calculate the target component's Total Attributed Cost. By checking the Cost Type Attribution field, the code only aggregates the cost types that are not selected. In addition, the code takes into account the specific weighting of the Cost Attribution Percentage.
def referenceTypes = ['Is Realized By', 'Is Supported By', 'Owns']
def defaultFieldNames = ['total_attributed_cost', 'total_direct_cost']
def toAPIFieldName = {
if (it.get() == 'No Attributed Cost Flow') return 'total_attributed_cost';
if (it.get() == 'No Direct Cost Flow') return 'total_direct_cost';
return '';
}
def getCostTypeAttributionFieldNames = {
values('cost_type_attribution').
unfold().
map(toAPIFieldName).
fold().
map{
fieldNamesToExclude = it.get()
defaultFieldNames.findAll{ defaultFieldName ->
!fieldNamesToExclude.contains(defaultFieldName)
}
}
}
def hasCostTypeAttribution = {
getCostTypeAttributionFieldNames().unfold().count().is(gt(0))
}
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(
union( // <-- This is new
coalesce(
outE(*referenceTypes).filter(hasCostTypeAttribution()).as('reference').
filter(hasCostTypeAttribution()).
map(
map(getCostTypeAttributionFieldNames()).unfold().as('fieldName').
project('percentage', 'totalCost').
by(
select('reference').
choose(
has('cost_attribution_percentage'),
values('cost_attribution_percentage'),
inV().
inE(*referenceTypes).as('otherReference').
project('fieldNamesOnOtherReference', 'fieldName').
by(getCostTypeAttributionFieldNames()).
by(select('fieldName')).
filter{ it.get().fieldNamesOnOtherReference.contains(it.get().fieldName) }.select('otherReference').outV().
where(eq('reference')).
by(label).
by(outV().label()).
count().
map{ 100 / it.get() }
)
).
by(
select('reference').
project('fieldName', 'component').
by(select('fieldName')).
by(inV()).
map{ it.get().component.property(it.get().fieldName).orElse(0) }
).
math('percentage * totalCost / 100').
sum()
).
sum(),
constant(0)
).map{ it.get().toInteger() }, // <-- The comma at the end here is new
__.in('ardoq_parent').values('total_attributed_cost', 'total_direct_cost').sum() // <-- This is new
).sum() // <-- This is new
)
Total Direct Cost
The Total Direct Cost Gremlin Code sums up the values of CAPEX and OPEX.
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(project('capex','opex').
by(coalesce(values('capex'), constant(0))).
by(coalesce(values('opex'), constant(0))).
math('capex + opex'))
Total Cost
The Total Cost Gremlin Code sums up the value of Total Attributed Cost and Total Direct Cost of the current Component Type and all it’s children.
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(values('total_direct_cost', 'total_attributed_cost').unfold().sum().map{ (it.get() as Double).round(0) })
Total Attribution Percentage
This Gremlin Code calculated the sum of a component's total Cost Attribution Percentages to other components. The cost allocation is divided into the target Component Type. For example, if an Application has specific weights on references to both Business and Technical Capabilities. Then the Gremlin Code will calculate the sum of Cost Attribution Percentages to Business and Technical Capabilities separately. A result could, for example, be “Technical Capability: 110%, Business Capability: 70%”
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(
inE().has('cost_attribution_percentage').
group().
by(otherV().label()).
by(values('cost_attribution_percentage').sum()).
map{ it.get().keySet().collect{ key -> "${key}: ${it.get().get(key)}%" }.join(', ') })
Cost Attribution Percent Data Quality
This code checks if the sum of the Cost Attribution Percentage from one given component to another Component Type exceeds 100%. If it does, the checkbox named Cost Attribution Percent Data Quality is set to ‘checked’.
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(
inE().has('cost_attribution_percentage').
group().
by(otherV().label()).
by(values('cost_attribution_percentage').sum()).
map{ it.get().values().any{percentage -> percentage > 100} })
Total Budgeted Cost
Equivalent to Total Cost, just for budgets. X = budget capex+budget opex
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(values('budget_capex', 'budget_opex').unfold().sum().map{ (it.get() as Double).round(0) })
Old versions:
Total Consumed Cost
This contains the Gremlin Code that aggregates the underlying components cost to the target component Total Consumed Cost. The code checks the field Cost Consumption, and only aggregates cost if it is checked. The code also takes into account the specific weighting in Cost Consumption Percentage.
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(coalesce(emit().repeat(__.in('ardoq_parent')).
outE().has('cost_consumption', true).as('percentage').inV().as('totalCost').
math('percentage * totalCost / 100').
by(choose(has('cost_consumption_percentage'),
values('cost_consumption_percentage'),
__.as('reference').inV().
inE().has('cost_consumption', true).outV().
where(eq('reference')).
by(label).
by(outV().label()).
count().
map{ 100 / it.get() }).math('floor _ ')).
by(values('total_attributed_cost', 'total_direct_cost').sum()).
sum(),
constant(0)
))
Total Cost:
The Total Cost Gremlin Code sums up the value of Total Consumed Cost and Total Direct Cost.
totaldirectcost = 'total_direct_cost'
totalconsumedcost = 'total_consumed_cost'
def calculateTotalCost(it) {
a=it.get().values(totaldirectcost)[0] as Double
b=it.get().values(totalconsumedcost)[0] as Double
return (a + b).round(2)
}
g.V(ids)
.and(
has(totaldirectcost),
has(totalconsumedcost))
.project('id', 'name', 'value').
by(id).
by('name').
by(map{calculateTotalCost(it)}) |
Total Consumption Percentage:
This Gremlin Code calculated the sum of a component's total Cost Consumption Percentages to other components. The cost allocation is divided into the target Component Type. For example if an Application has specific weights on references to both Business and Technical Capabilities. Then the Gremlin Code will calculate the sum of Cost Consumption Percentages to Business and Technical Capabilities separately. A result could, for example, be “Technical Capability: 110%, Business Capability: 70%”
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(
inE().has('cost_consumption_percentage').
group().
by(otherV().label()).
by(values('cost_consumption_percentage').sum()).
map{ it.get().keySet().collect{ key -> "${key}: ${it.get().get(key)}%" }.join(', ') }
) |
Cost Consumption Percent Data Quality:
The code checks if the sum of the Cost Consumption Percentage from one component to another component type exceeds 100%. The checkbox titled Cost Consumption Percent Data Quality is set to 'checked' when it does.
g.V(ids).
project('id', 'name', 'value').
by(id).
by('name').
by(
inE().has('cost_consumption_percentage').
group().
by(otherV().label()).
by(values('cost_consumption_percentage').sum()).
map{ it.get().values().any{percentage -> percentage > 100} }
) |
6. Support
Whether you are a new or an experienced customer, our technical support team will be available to help you overcome any knowledge or technical hurdles throughout the migration process. In Ardoq, select 'Chat with us'.