C3 AI Documentation Home

Custom Expression Engine Function

Functions available as part of the expression engine can be used in various layers in the C3 Agentic AI Platform including stored calculated fields, read calculated fields, canonical transform expressions, and metric expressions. You can also add a user-defined function when one is not available in the expression engine library.

Define a custom expression engine function

To define a custom expression engine function, you need to:

  • Create a custom function Type.

  • Declare a custom function.

  • Implement the logic within the custom function.

Create a custom function type

Create a Type that mixes ExpressionEngineFunction. For example, create the Type CustomFunction in the file CustomFunction.c3typ and mixin the ExpressionEngineFunction Type:

Type
type CustomFunction mixes ExpressionEngineFunction

The CustomFunction Type can now use functions from the ExpressionEngineFunction Type, such as, trim, isInfinity, or exponentialDecay.

Declare the custom functions

Declare the custom function under the Type that mixes ExpressionEngineFunction. For example modify the CustomFunction.c3typ Type as follows if the function is implemented in JavaScript:

Type
type CustomFunction mixes ExpressionEngineFunction {

  customFunc: function(a: int, b: double) : Timeseries js-server
}

Modify the CustomFunction Type to also indicate customFunc is implemented in Python:

Type
type CustomFunction mixes ExpressionEngineFunction {

  customFunc: function(a: int, b: double) : Timeseries py-server
}

Inside the body of the CustomFunction Type where the method customFunc is defined it is worth noting the difference in the properties. The python implementation uses py-server and the JavaScript version uses js-server.

Implement the logic for the custom function

Implement the logic for the custom function defined in the CustomFunction Type.

A JavaScript and Python implementation of the custom function is below.

JavaScript
function customFunc(a, b) {
  var result = SourceType.evalMetric({
    id: "foo",
    start: "2010-01-01",
    end: "2011-01-01",
    interval: "DAY",
    expression: "exponentialDecay(randomTimeseries(), randomTimeseries() > 0.9, " + a + ", " + b + ")"
  });

  return result.data();
}

Call a custom expression engine function

Below are several examples of how the custom expression function above, customFunc, can be called.

In a stored calculated field:

Type
entity type SourceType mixes MetricEvaluatable {

  x: int
  y: double

  z: Timeseries stored calc "customFunc(x, y)"
  ...
}

In a read calculated field:

Type
entity type SourceType {

  x: int
  y: double

  z: Timeseries calc "customFunc(x, y)"
  ...
}

In a canonical transform expression:

Type
type TransformCanonicalSourceTypeToTargetType mixes TargetType transforms CanonicalSourceType {

  z: ~ expression "customFunc(x, y)"
  ...
}

Where:

Type
type CanonicalSourceType {

  x: int
  y: double
  ...
}

And:

Type
entity type TargetType {

  z: Timeseries
  ...
}

You do not need to create a custom JavaScript transform anymore. Prefer using a custom expression engine function.

In a metric expression:

JSON
{
  "id": "CustomMetric_SourceType",
  "name": "CustomMetric",
  "srcType": "SourceType",
  "expression": "window('AVG', customFunc(x, y), -10, 10)"
}

Alternatively you can mixin the MetricFunctionLibrary Type to create custom expression engine functions. However, those functions can only be available in metric expressions and take the Timeseries Type as input (and optional other parameters) to return a Timeseries Type as output.

Debug a custom expression engine function

A custom expression engine function is declared by a method so all the debugging tips related to methods also apply.

Was this page helpful?