How to use variables in a Metric path or expression


#1

I would like to use a placeholder / variable when declaring a metric.
I have to be able to let the user pass a value in a metric expression at run time.
It would also allow me to factorize an expression in a SimpleMetric and to write N CompoundMetric with N different value for the variable.


#2
var sm = SimpleMetric.make({
  srcType: MyType, 
  name: "DataAccess",
  id: "DataAccess_WindTurbine",
  path: "measurements.(name == x)", // x is something we want to change
  expression:"avg(avg(normalized.data.quantity))",
  variables:[{ name: "x" }] // 
  })

// Now, define a CompoundMetric which uses the generic version and binds the variable to take a certain value.
var cm = CompoundMetric.make({
  id:"Elec", 
  name:"Elec", 
  expression:"DataAccess", 
  variables:[
    {name:"x", value:"active_power"}
    ]
  })

//Call evalMetrics / evalMetricsWithMetadata
var spec = {
  start:"2018-01-01", 
  end:"2018-02-01", 
  interval:"HOUR", 
  expressions:["Elec"], 
  ids:["myId"]}

var metrics = [sm, cm] // for evalMetricsWithMetadata you need to pass the generic metric and the binded compound metrics

MyType.evalMetricsWithMetadata(spec, metrics)

#3

It looks like you can also provide runtime values in the EvalMetricSpec itself (apparently only for compound metrics):

var sm = CompoundMetric.make({
  srcType: MyType, 
  name: "DataAccess",
  id: "DataAccess",
  expression:"SomeSimpleMetric * x",
  variables:[{ name: "x" }] // 
});

var spec = {
  start:"2018-01-01", 
  end:"2018-02-01", 
  interval:"HOUR", 
  expressions:["Elec"], 
  ids:["myId"],
  bindings: { "x": 4 }
};

MyType.evalMetricsWithMetadata(spec, [sm])

#4

@scott.kruyswyk It works for SimpleMetrics too:

SimpleMetric definition:

{
  "srcType": "MySrcType",
  "name": "MyMetric",
  "id": "MyMetric_MySrcType",
  "path": "measurements.(name == x)",
  "expression": "avg(avg(normalized.data.quantity))",
  "variables": [{ name: "x" }]
}

Then:

MySrcType.evalMetrics({
  start: "2018-01-01",
  end: "2018-02-01",
  interval: "HOUR",
  expressions: ["MyMetric"], 
  ids: ["myId"],
  bindings: { x: "measurement_series_name" }
});

#5

Ah ok that’s good to know - the spec makes it seem like it’s only for compound metrics:

This variable provides a way to provide values for fields at runtime for 
compound metrics 

#6

It seems that id and name of a CompoundMetric must be the same in order for evalMetricsWithMetadata to work?
Or, put differently, expressions of evalMetricsWithMetadata uses name for SimpleMetrics and id for CompoundMetrics. At least in v7.6.1.


#7

Can I use variables in a unit definition? See example where I want the units ID to be a variable? I guess alternatively I could force treatAsUnit within the expression

{
“id”: “OtherResourceConsumption_Organization”,
“name”: “OtherResourceConsumption”,
“srcType”: “Organization”,
“expression”: “sum(sum(normalized.data.consumption))”,
“path”: “denormChildren.(relationship == ‘PREL:OROL’).to.mappedFacilities.denormChildFacilities.services.(resource.id == resources_id)”,
“unit” : {
“id” : units_id
},
“cache”: {
“intervals”: [“MONTH”, “YEAR”],
“monthsInPast”: 36
},
“variables”: [ {
“name” : “resources_id”,
“dataType” : “string”
},
{
“name” : “units_id”,
“dataType” : “string”
}]
}


#8

Instead of this, you can wrap the expression with convertToUnit(YOUR_UNIT_AS_VAR, expression) and then you can pass the unit as a variable.

p.s. Also, just fyi, it is a bad idea to cache the metric during experimentation & using variables.


#9

thanks- got it on experimentation. Does cache with variables effectively open up risk of more caching than intended because all metric calls for org will cache?


#10

I believe that caching cannot work in the presence of variables (at least up to 7.6/7.8).