cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Recursive Services for Metric Roll-ups

Highlighted
Regular Member

Recursive Services for Metric Roll-ups

This is a useful trick for rolling up metrics in Thingworx across various levels of a hierarchy by using Networks, ThingShapes, and recursive service definitions.

Say that you have a hierachy of Things in your model such as a Global view, a Region view, and a Store view -- this could be a Mfg Plant, a Building, an Asset, etc; whatever the core metric producing Thing is in your model -- where your Store has KPIs that you want to roll up across regions and globally.

First, create a template for each of your hierarchical levels. In my case it is a GlobalTemplate, RegionalTemplate, and StoreTemplate. Add a property to your StoreTemplate that will be the KPI.

Now, create a Thing for the Globe, and each of your Regions and Stores. Add them to a hierachical Network as such:

Now, we need to create a ThingShape to aggregate our KPIs and apply it to the Global, Regional, and Store template.

Now we will define a recursive funciton on our ThingShape called GetKPI ​and define it with the following:

//define our base case, when the thing template we are on is the lowest level of our hierarchy, in this case the StoreTemplate

if (me.thingTemplate == "StoreTemplate") {

    //in our base case, the result is just the property for the metric we want to aggregate

    result = me.someMetric

} else {

    //otherwise, we are at some other level in the hierarchy and we need to get our child connections from the network

    //this gets all the things below us in the network

    var params = {

        name: me.name /* STRING */

    };

    // result: INFOTABLE dataShape: NetworkConnection

    var network = Networks["Network"].GetChildConnections(params);

    //loop through each of the things below us in the hierarchy and recursively add the result of GetKPI() to our result

    result = 0;

    for each (var row in network.rows) {

   

        result += Things[row.to].GetKPI();

    }

}

This is a simple case of just summing up a single property, but we can take this further using the Union and Aggregate snippets provided by thingworx to do other kinds of summarization. First add a new property called someAvgMetric ​to our StoreTemplate, and define a new service GetKPIProperties as such, with an InfoTable result, on the StoreTemplate

varparams = {

    propertyNames: {"items": ["someMetric", "someAvgMetric"]} /* JSON */

};

// result: INFOTABLE dataShape: "undefined"

var result = me.GetNamedProperties(params);

Now, define a new service on our ThingShape to utilize this service as our base case, and aggregate the resulting InfoTable when necessary. We'll call this service GetKPIAggregates:

//define our base case

if (me.thingTemplate == "StoreTemplate") {

    //this function will be on the StoreTemplate, and returns the base infotable

    result = me.GetKPIProperties()

} else {

    //grab our network

    var params = {

        name: me.name /* STRING */

    };

    // result: INFOTABLE dataShape: NetworkConnection

    var network = Networks["Network"].GetChildConnections(params);

    //need to create an empty infotable to union into. I glossed over this, but you'll need a datashape here

    //create empty infotable

    var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({ infoTableName: "InfoTable", dataShapeName: "KPIDataShape" });

    //loop through and union each of our results to our new infotable

    for each (var row in network.rows) {

        var params = {

            t1: result /* INFOTABLE */,

            t2: Things[row.to].GetKPIAggregates() /* INFOTABLE */

        };

        var result = Resources["InfoTableFunctions"].Union(params);

    }

    //aggregate each of our fields

    var params = {

        t: result /* INFOTABLE */,

        columns: "someMetric,someAvgMetric" /* STRING */,

        aggregates: "SUM,AVERAGE" /* STRING */,

        groupByColumns: undefined /* STRING */

    };

    // result: INFOTABLE

    var result = Resources["InfoTableFunctions"].Aggregate(params);

    //need to loop through each of our field names and make them match our base infotable

    // infotable datashape iteration

    var dataShapeFields = result.dataShape.fields;

    for (var fieldName in dataShapeFields) {

        var stringName = dataShapeFields[fieldName].name;

        var params = {

            t: result /* INFOTABLE */,

            from: stringName /* STRING */,

            to: stringName.split("_")[1] /* STRING */

        };

        // result: INFOTABLE

        var result = Resources["InfoTableFunctions"].RenameField(params);

    }

}

Now, in our mashups, we can use a DynamicThingShape and call our GetKPIs service at any level in our network, and our data will be aggregated correctly for whatever level we are at in the hierarchy!

Tags (2)