Advanced Mode for Configurable KPIs
Configure complex filters and calculations for KPIs using JSON.
Note
Advanced configuration for KPIs is only available in workspaces created before April, 2024.
Tutorial
The current KPI query format will be superseded by Facet Filters.
At the moment, Facet Filters do not support all functionalities needed to define a KPI. To make Configurable KPIs available now, KPI definitions use a custom JSON format. Facet Filters are planned to support KPIs in the future and will replace the custom JSON format.
If you want to create a KPI that cannot be defined in simple mode, you can switch to advanced mode. In advanced mode you can define a KPI using JSON format as shown in the image below.
A KPI can have one of three types:
- Simple KPI
- Computes one aggregated value over a list of filtered Fact Sheets.
- Percentage KPI
- Computes a value over a list of filtered Fact Sheets and a totalValue over a superset of Fact Sheets, e.g., the number of Applications with a valid Quality Seal and the number of all Applications.
- Group-By KPI
- Custom Group-By KPIs are currently not supported
Simple KPI
For a simple KPI, you only need to define a filter:
{
"filters":[
{
"type":"factSheetType",
"types":[
"Application"
]
}
]
}
A KPI with this definition returns the number of Fact Sheets with type Application in your workspace.
You can add another filter to get the number of Applications that are currently active:
{
"filters":[
{
"type":"factSheetType",
"types":[
"Application"
]
},
{
"type":"equals",
"fieldName":"lifecycle",
"fieldValue":"active",
"path":"$.currentPhase"
}
]
}
If you would rather not count active Applications but all Applications that are not end of life, you can combine a none
filter with an equals
filter:
{
"filters":[
{
"type":"factSheetType",
"types":[
"Application"
]
},
{
"type":"none",
"filters":[
{
"type":"equals",
"fieldName":"lifecycle",
"fieldValue":"endOfLife",
"path":"$.currentPhase"
}
]
}
]
}
LeanIX provides admins with predefined KPIs
Users don't have to reinvent the wheel: LeanIX provides users already with more than 50 KPI definitions that can be looked up in the workspace to understand the definition in the advanced JSON configuration, ready to be copied, modified and reused for the specific requirements of your organisation.
More Aggregations
Until now, all we did was count the number of Fact Sheets that match a specific filter, but you can also use other aggregations like sum or average. All available aggregations are listed here.
If you don't provide a specific aggregation, a KPI default to the count aggregation. You can define this explicitly like this:
{
"filters":[
"..."
],
"aggregations":[
{
"name":"value",
"operation":{
"type":"count"
}
}
]
}
The count operation is also special as it does not need an aggregatedField
. Other operations like average need to specify the aggregatedField
. The aggregated field must be a numeric field on the Fact Sheet.
{
"filters":[
"..."
],
"aggregations":[
{
"name":"avg",
"operation":{
"type":"avg"
},
"aggregatedField":"cost"
}
]
}
This aggregation yields the average cost over all filtered Fact Sheets. A simple KPI expects exactly one aggregation.
Aggregations on Tags and Tag Groups
Because of technical limitations you can currently not aggregate on tags or tag groups.
Aggregations on complex Fields
If you want to compute for example the average completion score over all Applications, aggregations are not powerful enough. This is because the completionScore
field on a Fact Sheet is not a simple numeric field, but an object, that holds the completion score for the complete Fact Sheet as well as scores for the different subsections.
To average the completion score, you need to use the fields key in the KPI definition. fields
can be used to define virtual Fact Sheet fields. For the completion score, we specify the base field we want to use (completionScore
) and the path
key pointing to the numeric value that should be used in the virtual field.
{
"filters":[
"..."
],
"fields":[
{
"name":"fsCompletion",
"factSheetType":"Application",
"definedAs":{
"type":"field",
"field":"completionScore",
"path":"$.completion"
}
}
]
}
Now we can define an aggregation on the virtual field fsCompletion
.
{
"filters":[
"..."
],
"fields":[
{
"name":"fsCompletion",
"factSheetType":"Application",
"definedAs":{
"type":"field",
"field":"completionScore",
"path":"$.completion"
}
}
],
"aggregations":[
{
"name":"avg",
"operation":{
"type":"avg"
},
"aggregatedField":"fsCompletion"
}
]
}
Percentage KPI
Percentage KPIs compute two values, which are used as nominator and denominator to calculate a percentage.
Next to filters
the KPI definition also needs totalFilter
, which defines the list of Fact Sheets used for calculating the denominator.
{
"filters":[
{
"type":"factSheetType",
"types":[
"Application"
]
},
{
"type":"none",
"filters":[
{
"type":"equals",
"fieldName":"lifecycle",
"fieldValue":"endOfLife",
"path":"$.currentPhase"
}
]
},
{
"type":"none",
"filters":[
{
"type":"equals",
"fieldName":"lxState",
"fieldValue":"DRAFT"
},
{
"type":"equals",
"fieldName":"lxState",
"fieldValue":"REJECTED"
}
]
},
{
"type":"none",
"filters":[
{
"type":"equals",
"fieldName":"technicalSuitability"
}
]
}
],
"totalFilter":[
{
"type":"factSheetType",
"types":[
"Application"
]
},
{
"type":"none",
"filters":[
{
"type":"equals",
"fieldName":"lifecycle",
"fieldValue":"endOfLife",
"path":"$.currentPhase"
}
]
}
]
}
If you define an aggregation, it is used for the nominator and the denominator.
Reference
Base Structure
KPI {
filters: Filter[],
totalFilter: Filter[],
fields: Field[],
aggregations: Aggregation[],
attributes: Attribute[]
}
Filters
Filter = FactSheetTypeFilter | ForAnyRelationFilter | ForAnyConstrainingRelation| ForFactSheetFilter | MatchesFilter | EqualsFilter | ContainsFilter | AllFilter | NoneFilter | AnyFilter | FullTextFilter | PathfinderFacetFilter;
FactSheetTypeFilter {
type: "factSheetType"
types: string[]
}
ForAnyRelationFilter {
type: "forAnyRelation"
relation: string
excludeTransitiveRelations: boolean = false
filters: Filter[]
}
ForAnyConstrainingRelationFilter {
type: "forAnyConstrainingRelation"
filters: Filter[]
}
ForFactSheetFilter {
type: "forFactSheet"
direction: "FROM" | "TO"
filters: Filter[]
}
LessThanFilter {
type: "less"
fieldValue: Object
fieldName: string
path?: string
}
LessOrEqualFilter {
type: "lessEqual"
fieldValue: Object
fieldName: string
path?: string
}
GreaterThanFilter {
type: "greater"
fieldValue: Object
fieldName: string
path?: string
}
GreaterOrEqualFilter {
type: "greaterEqual"
fieldValue: Object
fieldName: string
path?: string
}
FacetFilter {
facetKey: string
keys: string[]
}
EqualsFilter {
type: "equals"
fieldValue: Object
fieldName: string
path?: string
}
MatchesFilter {
type: "matches"
fieldValue: Object
fieldName: string
path?: string
}
ContainsFilter {
type: "contains"
fieldValue: Object
fieldName: string
path?: string
}
InFilter {
type: "in"
fieldName: string
fieldValue: Object[]
path?: string
}
AllFilter {
type: "all"
filters: Filter[]
}
AnyFilter {
type: "any"
filters: Filter[]
}
NoneFilter {
type: "none"
filters: Filter[]
}
Aggregations
Aggregation {
name: "someAggregation",
operation: Operation,
aggregatedField: "someField",
groupBy: "someOtherField",
}
Operations
Operation = Count | Sum | Min | Max | Avg
Count {
type: 'count'
}
Sum {
type: 'sum'
}
Min {
type: 'min'
}
Max {
type: 'max'
}
Avg {
type: 'avg'
}
Fields
Field {
name: "someName",
factSheetType: "Application",
definedAs: Path
}
Attributes
Attribute = FactSheetFieldAttribute | RelationFieldAttribute | RelatedFactSheetFieldAttribute | PathAttribute
enum AttributeType {
Field = "field",
RelationField = "relationField",
TargetField = "targetField"
Path = "path"
}
FactSheetFieldAttribute {
name: string
type: AttributeType.Field,
field: string
}
RelationFieldAttribute {
name: string
type: AttributeType.RelationField,
relation: string,
field: string
}
TargetFactSheetFieldAttribute {
name: string
type: AttributeType.TargetField,
relation: string,
field: string
}
PathAttribute {
name: string
type: AttributeType.Path,
path: Path
}
Paths
Path = FieldPath | RelationPath | FactSheetPath | ConstrainingRelationPath | PathsPath | AggregationPath
FieldPath {
type: 'field',
field: string
}
RelationPath {
type: 'relation',
relation: string,
path: Path,
filter: Filter,
excludeTransitiveRelations: boolean = true
}
FactSheetPath {
type: 'factsheet',
path: Path
}
ConstrainingRelationPath {
type: 'constrainingRelation',
path: Path
}
PathsPath {
type: 'paths',
paths: {
[name: string]: Path
}
}
AggregationPath {
type: 'aggregation',
operation: Operation,
path: Path
}
Special Paths
Lifecycle
$.phases.<phase>
$.duration.<phase>
(number of days from the start of the until the start of the next phase, or null if indefinite)
The following take the current date into account:
$.currentPhase
Current Lifecycle phase$.durationOfCurrentPhase
Duration of current Lifecycle phase$.sinceStart.<phase>
number of days from the start of the until the pointOfView date, or null if that date lies outside the phase$.sinceStartOfCurrentPhase
Days since the start of the current Lifecycle phase
Subscriptions
$.type
$.userId
$.linkedRoles.roleId
Location
$.rawAddress
$.latitude
$.longitude
$.geoCity
$.geoCountryCode
$.geoCountry
$.geoAddress
$.geoStreet
$.geoHouseNumber
$.geoPostalCode
ExternalID
$.externalId
$.comment
$.status
$.externalUrl
$.externalVersion
Updated 2 months ago