Port-to-Field Maps

Creating a Port-To-Field Map

When running an analytic, the Analytics Runtime service requires port-to-field maps that define where to get the analytic’s input data and how to handle the analytic’s output data. This mapping allows a single analytic to be reused across multiple orchestrations with different data sources.

About This Task

Each step in an orchestration requires its own port-to-field map. Follow these steps to create a port-to-field map. For more information about a map's fields and examples, see Port-To-Field Map Reference.

Procedure

  1. Complete the analyticName, analyticVersion, and common fields in the JSON structure.
  2. Complete the orchestrationStepId. The value is informational only. It does not correlate to any values in the input/output JSON structure.
  3. Create the iterations block. The analytics services framework supports multiple iterations of the same analytic.
  4. Define the inputMaps field in the iteration. This maps each input port in the analytic template to a data field.

    Each inputMap field can contain a Predix Time Series filter to narrow the dataset to be sent to the analytic. For more information about Time Series filters, see tss-using-service.html#concept_dc613f2c-bb63-4287-9c95-8aaf2c1ca6f7.

  5. Define the outputMaps field in the iteration. This maps each output port in the analytic template to a data field.
  6. Define the inputModelMaps field in the iteration if a referenced analytic requires trained models.

    For each orchestration step, the inputModelMaps field contains the list of modelName and modelVersion definitions required by the modelPort field definition in the Analytic Template. The value of the modelPortName is the correlation id between the port-to-field map and the Analytic Template model port. The value of the modelPortName in the port-to-field map must be the same as the value in the Analytic Template.

  7. Define the dataSourceId field for InputDataConnectorMap and OutputDataConnectorMap types. This field identifies the data source (persistent or temporary store) for the analytic input and output data for the analytics.

Port-To-Field Map Reference

An analytic template defines the format of its input and output JSON structure. The port-to-field map tells the runtime engine how to get the values to insert into the analytic’s input JSON structure and where to write the values from the analytic's output JSON structure. The port-to-field map simply maps FieldPort entries from the analytic's template to data sources and sinks.

The port-to-field map is itself a JSON structure. The JSON objects in this structure are summarized in the following tables.

Type: PortToFieldMap

This is the overall structure of a port-to-field map.

{
    "analyticName":<string>,
    "analyticVersion":<string>,
    "comment":<string>,
    "orchestrationStepId":<string>,
    "iterations":[<list of Iterations>]
}

See the following table for a description of the elements in a PortToFieldMap.

FieldDescription
analyticNameInformational only. It does not correlate with any values in the input/output JSON structure.
analyticVersionInformational only. It does not correlate with any values in the input/output JSON structure.
comment(Optional) Informational only. It does not correlate with any values in the input/output JSON structure.
orchestrationStepIdInformational only. It does not correlate with any values in the input/output JSON structure.
iterationsCreate one iteration entry as described below. The Analytics Framework also supports multiple iterations of the same analytic..

Type: Iteration

An iteration defines the set of input/output PortMaps for an execution of the analytic. Fill in the "inputMaps" array with the list of PortMaps that define how to get the input value and fill in the "outputMaps" with the list of OutputDataConnectorMaps that define where to write the output values.

This is the overall structure of an iteration object.

{
    "inputMaps":[<list of PortMaps>],
    "outputMaps":[<list of OutputDataConnectorMaps>],
    "inputModelMaps":[<list of ModelPortMaps>],
    "id":<string>,
    "name":<string>
}

See the following table for a description of the elements in an Iteration.

FieldDescription
inputMapsThe list of maps that associate (map) fields from the data source with objects in the JSON input structure.
outputMapsThe list of maps that map objects from the analytic's JSON output structure to fields in the data sink.
inputModelMapsThe list of maps that identify models to be passed to the analytic at runtime.
id(Optional). The analytic iteration id, must be a unique sequence. Can be useful to track an iteration which contains an error. Type string.
  • For single iteration — if id is missing, default value is "0".
  • For multiple iteration — if id is missing, default value is "0" for first iteration. Number will be increased by 1 for each subsequent iteration.
name(Optional). The description for the iteration. Type string.

Type: PortMap

Maps an object in the JSON input structure to a constant value or a field in the data source.

{
    "valueSourceType":<string>,
    "fullyQualifiedPortName":<string>
}
Extended by:
  • InputConstantMap
  • InputDataConnectorMap

See the following table for a description of the common elements in a PortMap.

FieldDescription
valueSourceTypeA flag indicating if the map is for a constant value (“CONSTANT") or is mapping the JSON object to a field in the data source (“DATA_CONNECTOR").
fullyQualifiedPortNameIdentifies the JSON object in the analytics’s input or output JSON structure that will hold the value from the field. The port name is a fully qualified (‘.’ delimited) string capturing the path from the root node in the JSON structure to the JSON object that will contain the value from the field in the data source. If the port was defined to be variable in the analytic template, that means the analytic is expecting an array of field values. In this case, each field value will need a separate PortMap with an index (‘.1’, ‘.2’, etc.) at the end of the fullyQualifiedPortName.

Type: InputConstantMap

An InputConstantMap is a type of PortMap to be used when the data to be provided to the analytic can be stored directly within the port-to-field map itself. This is the overall structure of an input constant map.

{
    "valueSourceType":<string>,
    "fullyQualifiedPortName":<string>,
    "value":<string>
}

Extends from: PortMap.

In addition to the common elements of a PortMap, an InputConstantMap holds the value of a constant field:

Field: value
Contains the value to be passed to the constant field. This can be a numeric value (without quotes) or a string value (with quotes).

A constant input value can be parametrized and passed in at runtime using the customAttributes field of OrchestrationExecutionRequest. For example:

{
    "valueSourceType":CONSTANT,
    "fullyQualifiedPortName":"data.abc",
    "value":"${custom.CONSTANT_VALUE}"
}

Type: InputDataConnectorMap

An InputDataConnectorMap is a type of PortMap to be used when the data to be provided to the analytic needs to be retrieved from the data source at runtime by the Analytics Data Connector. This is the overall structure of an input data connector map.

{
    "valueSourceType":<string>,
    "fullyQualifiedPortName":<string>,
    "fieldId":<string>,
    "dataSourceId":<string>,
    "queryCriteria":<string>,
    "engUnit":<string>,
    "variable":<boolean>,
    "tagNameQuery":<string>
}

Extends from: PortMap.

In addition to the common elements of a PortMap, an InputDataConnectorMap contains the following entries.

FieldDescription
fieldIdThe fieldId is a string that is mapped to a Predix Time Series tag id for a given asset id. At runtime the orchestration engine gets the Predix Time Series tag id for the field id (as described below), reads the value from Predix Time Series, and puts that value in the JSON object at the location corresponding to the fullyQualifiedPortName. The runtime acquires the Predix Time Series tag id for the field id as follows:
  • At runtime, an asset id is included in the orchestration request.
  • The request will also optionally contain a map of fieldId to Predix Time Series tag ids.
  • If the map in the request contains an entry for the field id, the runtime will use the Time Series tag id from that entry.
  • If the map in the request does not contain the field id, and if the InputDataConnectorMap contains a query in the tagNameQuery, the runtime will execute the query in Predix Asset to get the tag id.
  • If the tag id for this field id has not been found, the runtime will use the tenant's defaultTagQuery to retrieve the default map of field ids to Predix Time Series tag ids and it will get the Predix Time Series tag id for this InputDataConnectorMap's field id from this map.
dataSourceIdThe following values are supported:
  • "Temporary": This is a built-in data source. The data will be held in-memory for life of orchestration (temporary store).
  • "PredixTimeSeries": This is a built-in data source. The data will be held in Predix Time Series (persistent store) .
  • "external_data_store": the unique value you provide to identify the custom data connector service and its external data source. This value cannot begin with "Predix".
queryCriteria
  • For PredixTimeSeries data source, this field provides the Predix Time Series query string for retrieving the value from Predix Time Series. Note this string should not contain any Predix Time Series tag ids. The tag ids will be inserted at runtime as per the logic for mapping the fieldId to a Predix Time Series tag id (see fieldId description). Any tag ids in this query string will be overwritten.
  • To customize queryCriteria attributes, see Customizing Query Criteria Attributes in Port-to-Field Map.
  • For an external data source, the value defined in this field is passed to the custom data connector service when a read/write request is made.
  • Optional for Temporary data source.
engUnit(Optional) The engineering units of the data in this field.
variable(Optional) True when the value in the analytic's input or output JSON object is a JSON array. The array's values will be enclosed in [ ]. Default value is false.
tagNameQuery
  • (Optional) This field contains the GEL query for querying Predix Asset for the Predix Time Series tag id that will be used to retrieve the runtime value for the JSON object that corresponds with this InputDataConnectorMap's fullyQualifiedPortName. This query can be parametrized by the request's asset id and the InputDataConnectorMap's fieldId using the ${ASSET_ID} and ${FIELD_ID} variables.
  • To configure dynamic tags, see Configuring Dynamic Tags in Port-to-Field Map.

Type: OutputDataConnectorMap

An OutputDataConnectorMap is used to identify the destination of the output data generated by the analytic at runtime. This is the overall structure of an output data connector map.

{
    "fullyQualifiedPortName":<string>,
    "fieldId":<string>,
    "dataSourceId":<string>,
    "tagNameQuery":<string>
}

An OutputDataConnectorMap contains the following entries.

FieldDescription
fullyQualitifiedPortNameIdentifies the JSON object in the analytics’s output JSON structure that will hold the value from the field. The port name is a fully qualified (‘.’ delimited) string capturing the path from the root node in the JSON analytic output data to the JSON object that will contain the value of the field to be stored in the data sink. If the port was defined to be variable in the analytic template, that means the analytic will produce an array of field values. In this case, each field value will need a separate OutputDataConnectorPortMap with an index (‘.1’, ‘.2’, etc.) at the end of the fullyQualifiedPortName.
fieldIdThe field id is a string that is mapped to a Predix Time Series tag id for a given asset id. At runtime the orchestration engine gets the Predix Time Series tag id for the field id (described in InputDataConnectorMap fieldId description), and writes the value from JSON object at the location corresponding to the fullyQualitifedPortName to the Predix Time Series tag id.
dataSourceIdFor an OutputDataConnectorMap, multiple dataSourceIds can be specified using a comma delimited list. The following values are supported:
  • "Temporary": This is a built-in data source. The data will be held in-memory for life of orchestration (temporary store).
  • "PredixTimeSeries": This is a built-in data source. The data will be held in Predix Time Series (persistent store).
  • "external_data_store": the unique value you provide to identify the custom data connector service and its external data source. This value cannot begin with "Predix".
queryCriteria
tagNameQuery
  • (Optional) This field contains the GEL query for querying Predix Asset for the Predix Time Series tag id that will be used when writing the value from the JSON object that corresponds with this OutputDataConnectorMap's fieldId using the ${ASSET_ID} and ${FIELD_ID} variables.
  • To configure dynamic tags, see afs-reference.html#task_476c42a9-99df-4703-b172-d7e5872b0415.

Type: ModelPortMap

Note: modelPortMap type is supported in hierarchical analytic templates only. It is not supported in descriptive analytic templates.

A ModelPortMap is used to retrieve the specified model from the Runtime service. This model is then passed to the analytic at runtime by the Analytics Data Connector. This is the overall structure of a model port map.

{
    "modelPortName": <string>,
    "modelName": <string>,
    "modelVersion": <string>
}

See the following table for a description of the elements in a ModelPortMap.

FieldDescription
modelPortNameThe name the analytic uses to pull the model from a map of byte arrays.
modelNameThe name of the model stored in the Configuration service.
modelVersionThe version of the model stored in the Configuration service.

Customizing Query Criteria Attributes in Port-to-Field Map

The queryCriteria field (InputDataConnectorMap and OutputDataConnectorMap) in the port-to-field map provides the data retrieval instructions. The following examples show how to add custom attributes in the queryCriteria field when using Predix Time Series as a data source.

Pre-Defined System Attributes

System Attribute NameDescription
FIELD_IDThe field id of the port.
ASSET_IDThe asset instance id of the current orchestration run.
ANALYTIC_IDThe analytic id of the current orchestration step.
ORCHESTRATION_REQUEST_IDThe request id of the current orchestration run.
ORCHESTRATION_CONFIGURATION_IDThe orchestration configuration id of the current orchestration run.
ORCESTRATION_STEP_IDThe orchestration step id of the current orchestration run.
PORT_TO_FIELD_MAP_NAMEThe port-to-field map name of the current orchestration step.

Use Latest Data Point

Retrieve the latest datapoint from Predix Time Series service (instead of specifying tag ids) by omitting the start and end time in the port-to-field map's queryCriteria field. The following example shows how.

{
  "analyticName": "timeseriesAnalyticSampleWith3ColumnsAnd2Constants",
  "analyticVersion": "V1.0",
  "orchestrationStepId": "adjust temp by ambient",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.otherData.multipleTimeseries.0.MTSColumn1.0",
          "fieldId": "pressure sensor1",
          "queryCriteria": {
            "tags": [{
              "limit": 7,
              "order": "asc",
              "aggregations": [{
              ........
            }]
          },
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.otherData.multipleTimeseries.0.MTSColumn1.1",
          "fieldId": "pressure sensor1",
          "queryCriteria": {},
          "dataSourceId": "Predix Time Series"
        },
        ......

Use Parametrized Variables

You can use parametrized variables for resolving at orchestration runtime in the queryCriteria field. The following port-to-field map example shows how to do this in InputDataConnectorMap. The data must be consistent with Predix Time Series /datapoints request format.

{
  "analyticName": "4-input-timeseries-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "KW",
          "queryCriteria": {
            "start": "${custom.KW.START_TIME}",
            "end": "${custom.KW.END_TIME}",
            "tags": [{
              "limit": 1000,
              "order": "desc",
              "aggregations": [{
                "type": "${.custom.AGGREGATION_TYPE}",
                "interval": "${custom.INTERVAL}"
              }],
              "groups": [{
                "name": "${ATTRIBUTE_1_KEY}",
                "attributes": [
                  "${context.ASSET_ID}_${context.FIELD_ID}_${custom.KW.ATTRIBUTE_1_VALUE_1}",
                  "${context.ASSET_ID}_${context.FIELD_ID}_${custom.KW.ATTRIBUTE_1_VALUE_2}"
                ]
              }]
            }]
          },
.......
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": "${custom.vibration.START_TIME}",
            "end": "${custom.vibration.END_TIME}",
            "tags": [{
              "limit": 1000,
              "order": "desc",
              "aggregations": [{
                "type": "${custom.AGGREGATION_TYPE}",
                "interval": "${custom.INTERVAL}"
              }],
              "groups": [{
                "name": "${ATTRIBUTE_1_KEY}",
                "attributes": [
                  "${context.ASSET_ID}_${context.FIELD_ID}_${custom.vibration.ATTRIBUTE_1_VALUE_1}",
                  "${context.ASSET_ID}_${context.FIELD_ID}_${custom.vibration.ATTRIBUTE_1_VALUE_2}"
                ]
              }]
            }]
          },

When defining the OutputDataConnectorMap, note the following restrictions.

  • Output only supports key-value pairs of String datatype.
  • You must represent the Predix Time Series Web Socket write API structure.
  • messageId field is mandatory when writing to Time Series. Either provide hard coded value or a parametrized variable substituted at orchestration runtime.
  • If queryCriteria field is not specified for the output port, a system generated messageId and default attribute "source"="orchestration" key-value pair is added when writing to time series

The following is a sample queryCriteria in OutputDataConnectorMap.

........
 "outputMaps": [
  {
    "fullyQualifiedPortName": "data.time_series.sum",
    "fieldId": "bearing temperature final",
    "engUnit": "Celsius",
    "dataSourceId": "Predix Time Series",
    "queryCriteria" :     {
      "messageId": "${custom.MESSAGE_ID}",
      "body": [
       {
         "attributes": {
          "${custom.ATTRIBUTE_1_KEY}" : "${custom.ASSET_ID}_${custom.FIELD_ID}_${custom.bearing temperature final.ATTRIBUTE_1_VALUE_1}",
          "${custom.ATTRIBUTE_2_KEY}" : "${context.ASSET_ID}_${context.FIELD_ID}_${custom.bearing temperature final.ATTRIBUTE_1_VALUE_2}"
 
          }
        }
      ]
    }
.......

Provide block dynamic parametrized variables in queryCriteria field in InputDataConnectorMap as follows.

{
  "analyticName": "4-input-timeseries-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "KW",
          "queryCriteria": "${custom.QUERY_CRITERIA1}",
.......

Provide block dynamic parametrized variables in queryCriteria field in OutputDataConnectorMap as follows.

........
 "outputMaps": [
  {
    "fullyQualifiedPortName": "data.time_series.sum",
    "fieldId": "bearing temperature final",
    "engUnit": "Celsius",
    "dataSourceId": "Predix Time Series",
    "queryCriteria" :  "${custom.QUERY_CRITERIA2}"
.......

Configuring Dynamic Tags in Port-to-Field Map

When running an orchestration request using Predix Time Series tags, you can pass dynamic tags using customAttributes as a key-value pair. The following examples show how to do this.

Overview

The tagNameQuery field (InputDataConnectorMap and OutputDataConnectorMap) in the port-to-field map contains the GEL query for querying Predix Asset for the Predix Time Series tag id. Dynamic time series tags are supported by defining a dynamic tag template in the following format.

##${asset.sourceKey}.${context.portToFieldMapName}.${context.analyticId}.${custom.key}

Where,

tagNameQuery
Can contain either the dynamic time series tag or the asset GEL query to query the time series tag id.
##
Indicates this is a dynamic tag. Use dot-notation to identify the type of variable being used. The variables will have a context/namespace corresponding to where defined. The following namespaces are supported: "asset", "context", "custom".
${asset.sourceKey}
In the orchestration request, if the "assetSelectionFilter" is set to an asset GEL query, two assets will be returned as shown in the following sample. You can reference the asset attributes as ${asset.uri} , ${asset.sourceKey}, ${asset.name}, etc.
[
  {
    "uri": "/assets/32-3ed8356b-4c46-431e-b4e7-bb6371c39395",
    "classification": "/classifications/turbine",
    "sourceKey": "70101",
    "name": "Wolverine Ravine 1",
    "serial_number": "4610"
  },
  {
    "uri": "/assets/37-3ed8356b-4c46-431e-b4e7-bb6371c39395",
    "classification": "/classifications/turbine",
    "sourceKey": "70102",
    "name": "Wolverine Ravine 2",
    "serial_number": "4620"
  }
]
${context.portToFieldMapName}
"context" namespace includes: portToFieldMapName, analyticId, assetId, orchestrationStepId, orchestrationRequestId, orchestrationConfigurationId.
${custom.key}
Value is passed in by OrchestrationExecutionRequest as "customAttributes". In the following example, ${custom.key} will be replaced with "Hello World" .
{
  "orchestrationConfigurationId": "<Orchestration Configuration Id>",
  "assetId": null,
  "assetDataFieldsMap": null,
  "assetGroup": {
    "dataSourceId": "PredixAsset",
    "assetSelectionFilter": "/assets?filter=classification=/classifications/turbine:name=15sl-46606c64-619d-4db0-a059-bc2d879640ca<turbine_type"
  },
  "modelGroupKey": null,
  "dataSource": [
    {
      "dataSourceId": "Postgres Reference External Data Connector",
      "apiVersion": "v1",
      "baseUri": "http://localhost:18888"
    }
  ],
  "customAttributes": {
    "key": "Hello World"
  }
}

Note the following.

  • During orchestration execution, if the "tagNameQuery" is configured as dynamic tag in the port-to-field map, the defined format is processed as follows.
    • Orchestration context attributes, such as ANALYTIC_ID value, will replace ${context.analyticId}.
    • Asset parameter from orchestration execution request, such as sourceKey, will replace ${asset.sourceKey}.
    • portToFieldMap metadata attribute, like portToFieldMapName will replace ${context.portToFieldMapName}.
    • Then the processed value will be used as the tag name to write the data to the data source, and the entry will also be added to the tag map. If the same fieldId is used as an input in another portToFieldMap, the tag name can be found for reading the data from the data source.

Sample: Dynamic Tag in Port-to-Field Map Output Port

The following is an example of a dynamic tag defined in the port-to-field map output port (OutputDataConnectorMap).

{
  "analyticName": "java-timeseries-demo-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "KW",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669610
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": " PredixTimeSeries "
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray2",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "predixtimeseries"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "bearing_temperature",
          "tagNameQuery": "##${context.orchestrationRequestId}.${asset.serial_number}.${context.portToFieldMapName}.${context.fieldId}.${custom.ATTR_KEY1}",
          "engUnit": "Celsius",
          "dataSourceId": " Temporary , Predix Timeseries"
        },
        {
          "fullyQualifiedPortName": "data.time_series.diff",
          "fieldId": "local_windspeed",
          "tagNameQuery": "##${context.orchestrationRequestId}.${asset.serial_number}.${context.portToFieldMapName}.${context.fieldId}.${custom.ATTR_KEY1}",
          "engUnit": "Celsius",
          "dataSourceId": " Temporary , Predix Timeseries"
        }
      ]
    }
  ]
}

Pre-Defined System Attributes

The following pre-defined system attributes and custom attributes (from orchestration run request) are supported for parameter substitution.

System Attribute NameDescription
fieldIdThe field id of the port.
assetIdThe asset instance id of the current orchestration run.
analyticIdThe analytic id of the current orchestration step.
orchestrationRequestIdThe request id of the current orchestration run.
orchestrationConfigurationIdThe orchestration configuration id of the current orchestration run.
orchestrationStepIdThe orchestration step id of the current orchestration run.
portToFieldMapNameThe port-to-field-map name of the current orchestration step.

Sample: Custom Attributes in Orchestration Run Request

The following is a sample orchestration run request with "customAttributes" as key-value pair.

{
    "orchestrationConfigurationId": "a7d1c09d-000c-4017-a073-8a3df9058ffc",
    "assetId": null,
    "assetDataFieldsMap": null,
     "assetGroup": {
        "dataSourceId": "PredixAsset",
        "assetSelectionFilter": "/assets?filter=classification=/classifications/turbine:name=15sl-46606c64-619d-4db0-a059-bc2d879640ca<turbine_type"
    },
    "customAttributes": {   
        "ATTR_KEY1": "test_attr1"
    }
}

Note the following.

  • When the orchestration execution is completed, the dynamically created time series tags will be sent to the monitoring service.
  • You can query the monitoring service to read details about the dynamically generated time series tags for each orchestration execution.

Sample: Dynamic Tags in Orchestration Execution Result from Monitoring Service Query Response

The following is a sample orchestration execution result detail received from a monitoring service query response.

{
  "orchestrationRequestId": "74084eb3-680c-43b3-b8b6-e50979bb447d",
  "status": "COMPLETED",
  "orchestrationExecutionStatus": [
    {
      "contextId": "74084eb3-680c-43b3-b8b6-e50979bb447d-/assets/37-3ed8356b-4c46-431e-b4e7-bb6371c39395",
      "assetId": "/assets/37-3ed8356b-4c46-431e-b4e7-bb6371c39395",
      "status": "COMPLETED",
      "orchestrationStepStatus": [
        {
          "status": "COMPLETED",
          "analyticId": "adc54168-237e-4c13-8076-8de4359207a7",
          "analyticName": "Java Timeseries Demo Adder With Model - c81928a3-e76b-400b-a0ec-8b1b0b86778c",
          "analyticVersion": "v1",
          "analyticRequestId": "8c84e2af-f85b-11e6-9d69-ba7f8cc76dfa-sid-10001",
          "stepId": "sid-10001",
          "startTime": 1487698276520,
          "endTime": 1487698279280,
          "output": null,
          "errorResponse": null,
          "fieldTagMap": {
            "bearing_temperature": "74084eb3-680c-43b3-b8b6-e50979bb447d.4620.step1PortToFieldMapName.bearing_temperature.test_attr1",
            "local_windspeed": "74084eb3-680c-43b3-b8b6-e50979bb447d.4620.step1PortToFieldMapName.local_windspeed.test_attr1"
          }
        }
      ],
      "startTime": 1487698276460,
      "endTime": 1487698280700,
      "errorResponse": null
    },
    {
      "contextId": "74084eb3-680c-43b3-b8b6-e50979bb447d-/assets/32-3ed8356b-4c46-431e-b4e7-bb6371c39395",
      "assetId": "/assets/32-3ed8356b-4c46-431e-b4e7-bb6371c39395",
      "status": "COMPLETED",
      "orchestrationStepStatus": [
        {
          "status": "COMPLETED",
          "analyticId": "adc54168-237e-4c13-8076-8de4359207a7",
          "analyticName": "Java Timeseries Demo Adder With Model - c81928a3-e76b-400b-a0ec-8b1b0b86778c",
          "analyticVersion": "v1",
          "analyticRequestId": "8b8dff7d-f85b-11e6-9d69-ba7f8cc76dfa-sid-10001",
          "stepId": "sid-10001",
          "startTime": 1487698274900,
          "endTime": 1487698278040,
          "output": null,
          "errorResponse": null,
          "fieldTagMap": {
            "bearing_temperature": "74084eb3-680c-43b3-b8b6-e50979bb447d.4610.step1PortToFieldMapName.bearing_temperature.test_attr1",
            "local_windspeed": "74084eb3-680c-43b3-b8b6-e50979bb447d.4610.step1PortToFieldMapName.local_windspeed.test_attr1"
          }
        }
      ],
      "startTime": 1487698274840,
      "endTime": 1487698279810,
      "errorResponse": null
    }
  ],
  "errorResponse": null
}

Samples of Hierarchical Analytic Templates and Port-to-Field Maps

An analytic template is used at runtime in conjunction with a port-to-field map to control how the framework's runtime engine will handle the analytic input and output. The following are samples of hierarchical analytic templates and port-to-field maps.

Sample: DemoAdder Analytic

The following is a sample JSON input.

{
  "number1": <latest value from temperature sensor1>,
  "number2": -55
}

The following is a sample JSON output.

{"result" : <result from analytic>}

The following is a sample hierarchical analytic template.

{
  "analyticName": "add2Numbers",
  "analyticVersion": "V1.0",
  "inputPortDefinitions": [
    {
      "portType": "FIELD",
      "portName": "number1",
      "variable": false,
      "required": true
    },
    {
      "portType": "FIELD",
      "portName": "number2",
      "variable": false,
      "required": true
    }
  ],
  "outputPortDefinitions": [
    {
      "portType": "FIELD",
      "portName": "result",
      "variable": false,
      "required": true
    }
  ]
}

The following is a sample port-to-field map.

{
    "analyticName": "add2Numbers",
    "analyticVersion": "V1.0",
    "orchestrationStepId": "adjust temp by ambient",
    "iterations": [
        {
            "inputMaps": [
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "number1",
                    "fieldId": "temperature sensor1",
                    "queryCriteria": {"start": 1464989425852, "end": 1464989425852},
                    "dataSourceId": "PredixTimeSeries"
                },
                {
                    "valueSourceType": "CONSTANT",
                    "fullyQualifiedPortName": "number2",
                    "value": -55
                }
            ],
            "outputMaps": [
                {
                    "fullyQualifiedPortName": "result",
                    "fieldId": "adjusted temp",
                    "dataSourceId": "PredixTimeSeries"
                }
            ]
        }
    ]
}

Sample: Analytic Requiring a Time Series Table, Input Models, and Constants

Scenario: An analytic requires a time series table and two constants, where the time series input table has three fixed columns; column1, column2, and column3. Sample hierarchical analytic templates and port-to-field maps to support this scenario follow.

Note: All columns in the Time Series array will share the same time stamps. The quality attribute from Time Series is not supported.

The following is a sample JSON input.

{
  "inputData": {
 "data": {
        "timeseries": {
            "time_stamp": [
                000003242,
                000004242,
                000005242
            ],
            "column1": [
                10.0,
                20.0,
                30.0
            ],
            "column2": [
                1.0,
                2.0,
                3.0
            ],
            "column3": [
                0.1,
                0.2,
                0.3
            ]
        },
        "constants": {
            "constant1": 55,
            "constant2": 100
        }
    }

     },
  "inputModel": [
    {
      "modelPortName": "test-model-port-1",
      "isModelEmbedded": "true",
      "modelLib": "anVuay1tb2RlbC1iaW5hcnktMQ=="
    },
    {
      "modelPortName": "test-model-port-2",
      "isModelEmbedded": "true",
      "modelLib": "janVuay1tb2RlbC1iaW5hcnktMg=="
    }
  ]
}

{
    "data": {
        "timeseries": {
            "time_stamp": [
                000003242,
                000004242,
                000005242
            ],
            "column1": [
                10.0,
                20.0,
                30.0
            ],
            "column2": [
                1.0,
                2.0,
                3.0
            ],
            "column3": [
                0.1,
                0.2,
                0.3
            ]
        },
        "constants": {
            "constant1": 55,
            "constant2": 100
        }
    }
}

The following is a sample hierarchical analytic template.

{
    "analyticName": "analyticWith3ColumnsAnd2Constants",
    "analyticVersion": "V1.0",
    "inputPortDefinitions": [
        {
            "portType": "COMPOSITE",
            "portName": "data",
            "childrenPorts": [
                {
                    "portName": "timeseries",
                    "portType": "TIMESERIES_ARRAY",
                    "variable": false,
                    "columns": [
                        {
                            "portName": "column1",
                            "portType": "FIELD",
                            "variable": false,
                            "dataType": "DOUBLE_ARRAY",
                            "required": true
                        },
                        {
                            "portName": "column2",
                            "portType": "FIELD",
                            "variable": false,
                            "dataType": "DOUBLE_ARRAY",
                            "required": true
                        },
                        {
                            "portName": "column3",
                            "portType": "FIELD",
                            "variable": false,
                            "dataType": "DOUBLE_ARRAY",
                            "required": true
                        }
                    ]
                },
                {
                    "portType": "COMPOSITE",
                    "portName": "constants",
                    "childrenPorts": [
                        {
                            "portType": "FIELD",
                            "portName": "constant1",
                            "variable": false,
                            "dataSourceId": "PredixTimeSeries",
                            "required": true
                        },
                        {
                            "portType": "FIELD",
                            "portName": "constant2",
                            "variable": false,
                            "dataSourceId": "PredixTimeSeries",
                            "required": true
                        }
                    ]
                }
            ]
        }
    ],
,
"inputModelDefinitions": [
  {
    "modelPortName": "test-model-port-1"
  },
  {
    "modelPortName": "test-model-port-2"
  }
],

    "outputPortDefinitions" : [
        {
            "portType": "FIELD",
            "portName": "results",
            "variable": false,
            "dataSourceId": "PredixTimeSeries"
        }
    ]
}

The following is a sample port-to-field map.

{
    "analyticName": "timeseriesAnalyticSampleWith3ColumnsAnd2Constants",
    "analyticVersion": "V1.0",
    "orchestrationStepId": "adjust temp by ambient",
    "iterations": [
        {
            "inputMaps": [
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "data.timeseries.column1",
                    "fieldId": "temperature sensor",
                    "queryCriteria": {"start": 000003242, "end": 000005242},
                    "dataSourceId": "PredixTimeSeries"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "data.timeseries.column2",
                    "fieldId": "vibration sensor",
                    "queryCriteria": {"start": 000003242, "end": 000005242},
                    "dataSourceId": "PredixTimeSeries"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "data.timeseries.column3",
                    "fieldId": "pressure sensor",
                    "queryCriteria": {"start": 000003242, "end": 000005242},
                    "dataSourceId": "PredixTimeSeries"
                },
                {
                    "valueSourceType": "CONSTANT",
                    "fullyQualifiedPortName": "data.constants.constant1",
                    "value": -55
                },
                {
                    "valueSourceType": "CONSTANT",
                    "fullyQualifiedPortName": "data.constants.constant2",
                    "value": 100
                }
            ],
"inputModelMaps": [
  {
    "modelPortName": "test-model-port-1",
    "modelName": "test-model-1",
    "modelVersion": "v1"
  },
  {
    "modelPortName": "test-model-port-2",
    "modelName": "test-model-2",
    "modelVersion": "v1"
  }
],
            "outputMaps": [
                {
                    "fullyQualifiedPortName": "result",
                    "fieldId": "xxxField",
                    "dataSourceId": "PredixTimeSeries"
                }
            ]
        }
    ]
}

Sample: Analytic Requiring a Time Series Table With Variable Time Stamps

Scenario: An analytic requires a time series table and two constants, where the time series input table has three fixed columns; column1, column2, and column3 where time stamps are different. Sample hierarchical analytic templates and port-to-field maps to support this scenario follow.

Note: All columns in the Time Series array will not have the same time stamps. The quality attribute from Time Series is not supported.

The following is a sample JSON input.

{
  "time_series_temperature": {
    "temperature": [
      100
    ],
    "time_stamp": [
      "1455733669601"
    ]
  },
  "time_series_pressure": {
    "pressure": [
      57
    ],
    "time_stamp": [
      "1455733669605"
    ]
  },
  "time_series_vibration": {
    "vibration": [
      14
    ],
    "time_stamp": [
      "1455733669609"
    ]
  }
}

The following is a sample hierarchical analytic template.

{
  "analyticName": "analytic-name",
  "analyticVersion": "1.0",
  "inputPortDefinitions": [
    {
      "portName": "time_series_temperature",
      "portType": "TIMESERIES_ARRAY",
      "required": true,
      "variable": false,
      "columns": [
        {
          "portName": "temperature",
          "portType": "FIELD",
          "variable": false,
          "dataType": "DOUBLE_ARRAY",
          "required": true
        }
      ]
    },
    {
      "portName": "time_series_pressure",
      "portType": "TIMESERIES_ARRAY",
      "required": true,
      "variable": false,
      "columns": [
        {
          "portName": "pressure",
          "portType": "FIELD",
          "variable": false,
          "dataType": "DOUBLE_ARRAY",
          "required": true
        }
      ]
    },
    {
      "portName": "time_series_vibration",
      "portType": "TIMESERIES_ARRAY",
      "required": true,
      "variable": false,
      "columns": [
        {
          "portName": "vibration",
          "portType": "FIELD",
          "variable": false,
          "dataType": "DOUBLE_ARRAY",
          "required": true
        }
      ]
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "analytic-name",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "time_series_temperature.temperature",
          "fieldId": "field-7071",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669610
          },
          "engUnit": "Celsius",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "time_series_pressure.pressure",
          "fieldId": "field-2934",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669610
          },
          "engUnit": "Celsius",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "time_series_vibration.vibration",
          "fieldId": "field-9342",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669610
          },
          "engUnit": "Celsius",
          "required": true,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.result",
          "fieldId": "field-7432",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

Sample: Array of Arrays Model

This example shows how you can create an hierarchical analytic template that represents JSON input data as an array of arrays when starting with input data similar to the following:

"Target_data": [
    [-1.3902596851290876, -6.765816812041471, -4.76418388526832, -1.2112080900902589, -1.7569610822677713], 
    [9.7817179641162, -1.145749275218344, 6.533089409154036, 6.549142463394793, -5.168794582523],
    [-0.44253227413493945, -6.43586397529881, -3.291613230961093, 1.2406735399676179, -1.4659275851421456],
    [0.01589916825431556, -4.695552518057381, -5.284477375577028, -1.9252859877753656, -2.865932498974862]....

Start by marking the analytic input port as a variable port in the analytic template.

{
  "analyticName": "analytic-with-variable-input-port",
  "analyticVersion": "1.0",
  "inputPortDefinitions": [
    {
      "portType": "FIELD",
      "portName": "Target_data",
      "variable": true,
      "dataType": "DOUBLE_ARRAY",
      "required": true
    }
  ],
  "outputPortDefinitions": [
    {
      "portName": "output",
      "portType": "FIELD",
      "variable": false,
      "dataType": "DOUBLE_ARRAY",
      "required": true
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "analytic-with-variable-input-port",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "Target_data.0",
          "fieldId": "KW",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "Target_data.1",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "output",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

When the orchestration is run, the data input will come from two time series tags. The data input will look as follows.

{
  "Target_data": [
    [
      5,
      6,
      7,
      8,
      9,
      10
    ],
    [
      500,
      600,
      700,
      800,
      900,
      1000
    ]
  ]
}

You can add more data array to the top level array by defining Target_data.2, Target_data.3, and so on.

Sample: Multiple Iterations of Same Analytic

This example shows how you can run multiple iterations of the same analytic in an orchestration execution. The following is a sample port-to-field map.

{
  "analyticName": "demo-timeseries-adder",
  "analyticVersion": "V1",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "id": "0",
      "name": " First Iteration",
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "temperature sensor",
          "queryCriteria": {
            "start": 0,
            "end": -1
          },
          "dataSourceId": "PredixTimeSeries"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray2",
          "fieldId": "vibration sensor",
          "queryCriteria": {
            "start": 0,
            "end": -1
          },
          "dataSourceId": "PredixTimeSeries"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "demo sum",
          "dataSourceId": "PredixTimeSeries"
        }
      ]
    },
    {
      "id": "1",
      "name": " Second Iteration",
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "temperature sensor",
          "queryCriteria": {
            "start": 0,
            "end": -1
          },
          "dataSourceId": "PredixTimeSeries"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray2",
          "fieldId": "vibration sensor",
          "queryCriteria": {
            "start": 0,
            "end": -1
          },
          "dataSourceId": "PredixTimeSeries"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "demo sum",
          "dataSourceId": "PredixTimeSeries"
        }
      ]
    }
  ]
}

Sample: Analytic Requiring Predix Time Series Data Using an Array of Tags

This example shows how you can run an analytic that uses Predix Time Series data that is an array of tags. For steps to run the orchestration request, see afs-orchestration-execution.html#task_9d270d7f-4d4a-4e07-9239-f121d17f1c8d.

The following is a sample hierarchical analytic template.


{
  "analyticName": "java-timeseries-demo-adder",
  "analyticVersion": "1.0",
  "inputPortDefinitions": [
    {
      "portType": "COMPOSITE",
      "portName": "data",
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series_1",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "doubleArray",
              "portType": "FIELD",
              "variable": true,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            }
          ]
        },
        {
          "portName": "time_series_2",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "integerArray",
              "portType": "FIELD",
              "variable": true,
              "dataType": "INTEGER_ARRAY",
              "required": true
            }
          ]
        }
      ]
    }
  ],
  "outputPortDefinitions": [
    {
      "portName": "data",
      "portType": "COMPOSITE",
      "required": true,
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "sum",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            }
          ]
        }
      ]
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "4-input-timeseries-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_1.doubleArray",
          "fieldId": "doubleArrayFieldId",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669603
          },
          "engUnit": "hertz",
          "required": true,
          "variable": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_2.integerArray",
          "fieldId": "integerArrayFieldId",
          "queryCriteria": {
            "start": 1455733669901,
            "end": 1455733669904
          },
          "engUnit": "kw",
          "required": true,
          "variable": true,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

The array of tags is passed in through the orchestrationConfigurationID definition as shown in the following example.

{
  "orchestrationConfigurationId": "3a5cd1da-5b6e-47fd-b74d-9e75e959810f",
  "assetDataFieldsMap": {
    "doubleArrayFieldId": [
      "timerseries_tag1",
      "timerseries_tag2",
      "timerseries_tag3"
    ],
    "integerArrayFieldId": [
      "timerseries_tag4",
      "timerseries_tag5"
    ]
  },
  "dataSource": []
}

The following shows a sample of generated input with data.

{
  "inputData": {
    "data": {
      "time_series_1": {
        "time_stamp": [
          1455733669601,
          1455733669602,
          1455733669603
        ],
        "doubleArray": [
          [
            500,
            600,
            700
          ],
          [
            5000,
            6000,
            7000
          ],
          [
            50000,
            60000,
            70000
          ]
        ]
      },
      "time_series_2": {
        "time_stamp": [
          1455733669901,
          1455733669902,
          1455733669903,
          1455733669904
        ],
        "integerArray": [
          [
            105,
            205,
            305,
            405
          ],
          [
            15,
            25,
            35,
            45
          ]
        ]
      }
    }
  }
}

Sample: Analytic Requiring Predix Time Series Data Using Variable Input Ports

This example shows how you can run an analytic that uses data having separate timestamps for each indexed block of generated data from Predix Time Series (variable input port).

The following is a sample hierarchical template format with variable ports.

Note: When the portType value is TIMESERIES_ARRAY, the timestampShared value must be false to indicate that variable ports are being used.
{
  "analyticName": "sample-hirerachical-analytic-template-with-two-variable-ports",
  "analyticVersion": "1.0",
  "inputPortDefinitions": [
    {
      "portType": "COMPOSITE",
      "portName": "data",
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series_1",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "doubleArray",
              "portType": "FIELD",
              "variable": true,
              "timestampShared": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            }
          ]
        },
        {
          "portName": "time_series_2",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "integerArray",
              "portType": "FIELD",
              "variable": true,
              "timestampShared": false,
              "dataType": "INTEGER_ARRAY",
              "required": true
            }
          ]
        }
      ]
    }
  ],
  "outputPortDefinitions": [
    {
      "portName": "data",
      "portType": "COMPOSITE",
      "required": true,
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "sum",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            }
          ]
        }
      ]
    }
  ]
}

The following is a sample port-to-field map showing that separate timestamps for each block of data is needed.

{
  "analyticName": "sample-port-to-field-map-with-two-variable-ports",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_1.doubleArray.0",
          "fieldId": "vibration1",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669603
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_1.doubleArray.1",
          "fieldId": "vibration2",
          "queryCriteria": {
            "start": 1455733669701,
            "end": 1455733669705
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_1.doubleArray.2",
          "fieldId": "vibration3",
          "queryCriteria": {
            "start": 1455733669801,
            "end": 1455733669802
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_2.integerArray.0",
          "fieldId": "kw1",
          "queryCriteria": {
            "start": 1455733669601,
            "end": 1455733669603
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series_2.integerArray.1",
          "fieldId": "kw2",
          "queryCriteria": {
            "start": 1455733669701,
            "end": 1455733669705
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

The following is sample generated analytic input for a hierarchical template showing separate timestamps side-by-side with values.

{
  "data": {
    "time_series_1": {
      "doubleArray": [
        {
          "time_stamp": [
            1455733669601,
            1455733669602,
            1455733669603
          ],
          "values": [
            500,
            600,
            700
          ]
        },
        {
          "time_stamp": [
            1455733669701,
            1455733669702,
            1455733669703,
            1455733669704,
            1455733669705
          ],
          "values": [
            50,
            60,
            70,
            80,
            90
          ]
        },
        {
          "time_stamp": [
            1455733669801,
            1455733669802
          ],
          "values": [
            1000,
            2000
          ]
        }
      ]
    },
    "time_series_2": {
      "integerArray": [
        {
          "time_stamp": [
            1455733669101,
            1455733669102,
            1455733669103,
            1455733669104
          ],
          "values": [
            105,
            205,
            305,
            405
          ]
        },
        {
          "time_stamp": [
            1455733669101,
            1455733669202,
            1455733669203,
            1455733669204,
            1455733669205,
            1455733669206
          ],
          "values": [
            15,
            25,
            35,
            45,
            55,
            65
          ]
        }
      ]
    }
  }
}

When creating the orchestration execution request payload, pass the array type of data in assetDataFieldsMap for the fieldId. For example,

{
  "orchestrationConfigurationId": "3a5cd1da-5b6e-47fd-b74d-9e75e959810f",
  "assetDataFieldsMap": {
    "doubleArrayFieldId": [
      "timerseries_tag1",
      "timerseries_tag2",
      "timerseries_tag3"
    ],
    "integerArrayFieldId": [
      "timerseries_tag4",
      "timerseries_tag5"
    ]
  },
  "dataSource": []
}

The following is sample generate input for two timeseries variable ports.

{
  "inputData": {
    "data": {
      "time_series_1": {
        "time_stamp": [
          1455733669601,
          1455733669602,
          1455733669603
        ],
        "doubleArray": [
          [
            500,
            600,
            700
          ],
          [
            5000,
            6000,
            7000,
            8000,
            9000
          ],
          [
            50000,
            60000
          ]
        ]
      },
      "time_series_2": {
        "time_stamp": [
          1455733669101,
          1455733669102,
          1455733669103,
          1455733669104
        ],
        "integerArray": [
          [
            105,
            205,
            305,
            405
          ],
          [
            15,
            25,
            35,
            45,
            55,
            65
          ]
        ]
      }
    }
  }
}

Sample: Reusing a Port-to-Field Map When Providing Data Is Optional

Scenario: You may want to use the same port-to-field map for multiple deployments but need to vary which ports will have data mapped for certain iterations. In the InputMaps definition, you can set the required field to false to indicate that data is optional. When this port is marked optional (required: false) and data is not provided during execution, it will be ignored and execution will not be failed for missing data. The following examples show how you can achieve this.

The following is a sample hierarchical analytic template

{
  "analyticName": "java-timeseries-demo-adder",
  "analyticVersion": "1.0",
  "inputPortDefinitions": [
    {
      "portType": "COMPOSITE",
      "portName": "data",
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "numberArray1",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            },
            {
              "portName": "numberArray2",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            },
            {
              "portName": "numberArray3",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": false
            }
          ]
        }
      ]
    }
  ],
  "outputPortDefinitions": [
    {
      "portName": "data",
      "portType": "COMPOSITE",
      "required": true,
      "variable": false,
      "childrenPorts": [
        {
          "portName": "time_series",
          "portType": "TIMESERIES_ARRAY",
          "required": true,
          "variable": false,
          "columns": [
            {
              "portName": "sum",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": true
            },
            {
              "portName": "diff",
              "portType": "FIELD",
              "variable": false,
              "dataType": "DOUBLE_ARRAY",
              "required": false
            }
          ]
        }
      ]
    }
  ]
}

The following is a sample descriptive analytic template.

{
  "name": "TimeseriesAdder",
  "description": "",
  "packageName": "",
  "codeLanguage": "JAVA",
  "version": "1.0.0",
  "author": "Predix Analytics team",
  "inputDataPortDefinitions": [
    {
      "name": "time_series",
      "description": "",
      "dataType": "TimeSeries",
      "valueRequired": true,
      "variable": true,
      "arrayDimensions": 0
    },
    {
      "timeSeriesName": "time_series",
      "name": "numberArray1",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": true,
      "validators": [
        "NotNull()",
        "IsNumber()"
      ],
      "arrayDimensions": 1
    },
    {
      "timeSeriesName": "time_series",
      "name": "numberArray2",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": true,
      "validators": [
        "NotNull()",
        "IsNumber()"
      ],
      "arrayDimensions": 1
    },
    {
      "timeSeriesName": "time_series",
      "name": "numberArray3",
      "description": "",
      "dataType": "Double",
      "valueRequired": false,
      "variable": true,
      "validators": [
        "NotNull()",
        "IsNumber()"
      ],
      "arrayDimensions": 1
    }
  ],
  "constantDataPortDefinitions": [
    {
      "timeSeriesName": "time_series",
      "name": "sum",
      "description": "",
      "dataType": "Custom",
      "valueRequired": true,
      "variable": true,
      "arrayDimensions": 1
    },
    {
      "timeSeriesName": "time_series",
      "name": "diff",
      "description": "",
      "dataType": "Boolean",
      "valueRequired": false,
      "variable": true,
      "validators": [
        "NotNull()",
        "IsNumber()"
      ],
      "arrayDimensions": 1
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "4-input-timeseries-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray1",
          "fieldId": "KW",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray2",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "data.time_series.numberArray3",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": false,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "data.time_series.sum",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "fullyQualifiedPortName": "data.time_series.diff",
          "fieldId": "windspeed final",
          "engUnit": "km",
          "required": false,
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

Sample generated input with data for optional (required: false) field.

{
    "data": {
      "time_series": {
        "time_stamp": [
          1455733669605,
          1455733669606,
          1455733669607,
          1455733669608,
          1455733669609,
          1455733669610
        ],
        "numberArray1": [
          5.0,
          6.0,
          7.0,
          8.0,
          9.0,
          10.0
        ],
        "numberArray2": [
          500.0,
          600.0,
          700.0,
          800.0,
          900.0,
          1000.0
        ],
       "numberArray3": [
          50.0,
          60.0,
          70.0,
          80.0,
          90.0,
          100.0
        ]
      }
    }
}

Sample generated input without data for optional (required: false) field.

{
    "data": {
      "time_series": {
        "time_stamp": [
          1455733669605,
          1455733669606,
          1455733669607,
          1455733669608,
          1455733669609,
          1455733669610
        ],
        "numberArray1": [
          5.0,
          6.0,
          7.0,
          8.0,
          9.0,
          10.0
        ],
        "numberArray2": [
          500.0,
          600.0,
          700.0,
          800.0,
          900.0,
          1000.0
        ]
      }
    }
}

Samples of Descriptive Analytic Templates and Port-to-Field Maps

An analytic template is used at runtime in conjunction with a port-to-field map to control how the framework's runtime engine will handle the analytic input and output. The following are samples of descriptive analytic templates and port-to-field maps.

Sample: Analytic Adder with Double Array Ports

The following is a sample JSON input.

{
  "internalRecords": [],
  "records": [
    {
      "type": "DOUBLE",
      "name": "numberArray1",
      "data": [
        5.0,
        6.0,
        7.0,
        8.0,
        9.0,
        10.0
      ],
      "arraySizes": [
        6
      ]
    },
    {
      "type": "DOUBLE",
      "name": "numberArray2",
      "data": [
        500.0,
        600.0,
        700.0,
        800.0,
        900.0,
        1000.0
      ],
      "arraySizes": [
        6
      ]
    }
  ],
  "timeSeriesRecords": []
}

The following is a sample JSON output.

{
  "records": [
    {
      "type": "DOUBLE",
      "name": "results",
      "data": [
        505.0,
        606.0,
        707.0,
        808.0,
        909.0,
        1010.0
      ],
      "arraySizes": [
        6
      ]
    }
  ]
}

The following is a sample descriptive analytic template.

{
  "name": "DoubleArrayAdder",
  "description": "",
  "packageName": "",
  "codeLanguage": "JAVA",
  "version": "1.0.0",
  "author": "Predix Analytics team",
  "inputDataPortDefinitions": [
    {
      "name": "numberArray1",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": false,
      "arrayDimensions": 1
    },
    {
      "name": "numberArray2",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": false,
      "arrayDimensions": 1
    }
  ],
  "outputDataPortDefinitions": [
    {
      "name": "results",
      "description": "",
      "dataType": "Double",
      "valueRequired": false,
      "variable": false,
      "arrayDimensions": 1
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "DoubleArrayAdder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "numberArray1",
          "fieldId": "KW",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "numberArray2",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "results",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

Sample: Analytic Adder with Timeseries and Constant Ports

Scenario: An analytic requires a time series table and one constant, where the time series input table has two fixed columns; numberArray1 and numberArray2. Sample analytic templates and port-to-field maps to support this scenario follow.

Note:

All columns in the Time Series array will share the same time stamps. The quality attribute from Time Series is not supported.

The following is a sample JSON input.

{
    "internalRecords": [],
    "records": [
        {
            "type": "DOUBLE",
            "name": "constant1",
            "data": [
                55.0
            ],
            "arraySizes": [
                1
            ]
        }
    ],
    "timeSeriesRecords": [
        {
            "name": "time_series",
            "timestamps": [
                "2016-02-17T18:27:49.601",
                "2016-02-17T18:27:49.602",
                "2016-02-17T18:27:49.603"
            ],
            "data": [
                {
                    "type": "DOUBLE",
                    "name": "numberArray1",
                    "data": [
                        1.0,
                        2.0,
                        3.0
                    ],
                    "arraySizes": [
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "numberArray2",
                    "data": [
                        100.0,
                        200.0,
                        300.0
                    ],
                    "arraySizes": [
                        3
                    ]
                }
            ]
        }
    ]
}

The following is a sample analytic output.

{
  "internalRecords": [],
  "records": [],
  "timeSeriesRecords": [
    {
      "name": "time_series",
      "timestamps": [
        "2016-02-17T18:27:49.601",
        "2016-02-17T18:27:49.602",
        "2016-02-17T18:27:49.603"
      ],
      "data": [
        {
          "type": "DOUBLE",
          "name": "results",
          "data": [
            101.0,
            202.0,
            303.0
          ],
          "arraySizes": [
            3
          ]
        }
      ]
    }
  ]
}

The following is a sample descriptive analytic template.

{
  "name": "TimeseriesAdder",
  "description": "",
  "packageName": "",
  "codeLanguage": "JAVA",
  "version": "1.0.0",
  "author": "Predix Analytics team",
  "inputDataPortDefinitions": [
    {
      "name": "time_series",
      "description": "",
      "dataType": "TimeSeries",
      "valueRequired": false,
      "variable": false,
      "arrayDimensions": 0
    },
    {
      "timeSeriesName": "time_series",
      "name": "numberArray1",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": false,
      "arrayDimensions": 1
    },
    {
      "timeSeriesName": "time_series",
      "name": "numberArray2",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": false,
      "arrayDimensions": 1
    }
  ],
  "constantDataPortDefinitions": [
    {
      "name": "constant1",
      "description": "",
      "dataType": "Double",
      "valueRequired": true,
      "variable": false,
      "arrayDimensions": 0
    }
  ],
  "outputDataPortDefinitions": [
    {
      "name": "time_series",
      "description": "",
      "dataType": "TimeSeries",
      "valueRequired": false,
      "variable": false,
      "arrayDimensions": 0
    },
    {
      "timeSeriesName": "time_series",
      "name": "results",
      "description": "",
      "dataType": "Double",
      "valueRequired": false,
      "variable": false,
      "arrayDimensions": 1
    }
  ]
}

The following is a sample port-to-field map.

{
  "analyticName": "timeseries-adder",
  "analyticVersion": "1.0",
  "orchestrationStepId": "sid-10001",
  "iterations": [
    {
      "inputMaps": [
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "time_series.numberArray1",
          "fieldId": "KW",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "kw",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "time_series.numberArray2",
          "fieldId": "vibration",
          "queryCriteria": {
            "start": 1455733669605,
            "end": 1455733669610
          },
          "engUnit": "hertz",
          "required": true,
          "dataSourceId": "Predix Time Series"
        },
        {
          "valueSourceType": "DATA_CONNECTOR",
          "fullyQualifiedPortName": "constant1",
          "fieldId": "engineType",
          "queryCriteria": {
            "columns": [
              "data_value"
            ],
            "table": "sensor_data",
            "conditions": [
              {
                "key": "asset_id",
                "value":"${ASSET_ID}",
                "valueType": "string",
                "relation": " = "
              },
              {
                "key": "field_id",
                "value": "engineType",
                "valueType": "string",
                "relation": " = "
              }
            ]
          },
          "required": true,
          "dataSourceId": "Custom Data Source"
        }
      ],
      "outputMaps": [
        {
          "fullyQualifiedPortName": "time_series.results",
          "fieldId": "bearing temperature final",
          "engUnit": "Celsius",
          "dataSourceId": "Predix Time Series"
        }
      ]
    }
  ]
}

Sample: Analytic Adder with Variable Timeseries Ports

The following is a sample JSON input.

{
    "internalRecords": [],
    "records": [],
    "timeSeriesRecords": [
        {
            "name": "time_series",
            "timestamps": [
                "2016-02-17T18:27:49.601",
                "2016-02-17T18:27:49.602",
                "2016-02-17T18:27:49.603"
            ],
            "data": [
                {
                    "type": "DOUBLE",
                    "name": "temperature_2",
                    "data": [
                        1.0,
                        2.0,
                        3.0
                    ],
                    "arraySizes": [
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "temperature_5",
                    "data": [
                        5.0,
                        6.0,
                        7.0
                    ],
                    "arraySizes": [
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "vibration_2",
                    "data": [
                        100.0,
                        200.0,
                        300.0
                    ],
                    "arraySizes": [
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "vibration_5",
                    "data": [
                        500.0,
                        600.0,
                        700.0
                    ],
                    "arraySizes": [
                        3
                    ]
                }
            ]
        }
    ]
}

The following is a sample JSON output.

{
    "internalRecords": [],
    "records": [],
    "timeSeriesRecords": [
        {
            "name": "time_series",
            "timestamps": [
                "2016-02-17T18:27:49.601",
                "2016-02-17T18:27:49.602",
                "2016-02-17T18:27:49.603"
            ],
            "data": [
                {
                    "type": "DOUBLE",
                    "name": "results_2",
                    "data": [
                        101.0,
                        202.0,
                        303.0
                    ],
                    "arraySizes": [
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "results_5",
                    "data": [
                        505.0,
                        606.0,
                        707.0
                    ],
                    "arraySizes": [
                        3
                    ]
                }
            ]
        }
    ]
}

The following is a sample descriptive analytic template.

{
    "name": "TimeseriesAdder",
    "description": "",
    "packageName": "",
    "codeLanguage": "JAVA",
    "version": "1.0.0",
    "author": "Predix Analytics team",
    "inputDataPortDefinitions": [
        {
            "name": "time_series",
            "description": "",
            "dataType": "TimeSeries",
            "valueRequired": false,
            "variable": false,
            "arrayDimensions": 0
        },
        {
            "timeSeriesName": "time_series",
            "name": "temperature",
            "description": "",
            "dataType": "Double",
            "valueRequired": true,
            "variable": true,
            "arrayDimensions": 1
        },
        {
            "timeSeriesName": "time_series",
            "name": "vibration",
            "description": "",
            "dataType": "Double",
            "valueRequired": true,
            "variable": true,
            "arrayDimensions": 1
        }
    ],
    "outputDataPortDefinitions": [
        {
            "name": "time_series",
            "description": "",
            "dataType": "TimeSeries",
            "valueRequired": false,
            "variable": false,
            "arrayDimensions": 0
        },
        {
            "timeSeriesName": "time_series",
            "name": "results",
            "description": "",
            "dataType": "Double",
            "valueRequired": false,
            "variable": true,
            "arrayDimensions": 1
        }
    ]
}

The following is a sample port-to-field map.

{
    "analyticName": "timeseries-adder",
    "analyticVersion": "1.0",
    "orchestrationStepId": "sid-10001",
    "iterations": [
        {
            "inputMaps": [
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.temperature_2",
                    "fieldId": "temp.left",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.temperature_5",
                    "fieldId": "temp.right",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.vibration_2",
                    "fieldId": "vibration.left",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.vibration_5",
                    "fieldId": "vibration.right",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                }
            ],
            "outputMaps": [
                {
                    "fullyQualifiedPortName": "time_series.results_2",
                    "fieldId": "results.left",
                    "dataSourceId": "Predix Time Series"
                }
                {
                    "fullyQualifiedPortName": "time_series.results_5",
                    "fieldId": "results.right",
                    "dataSourceId": "Predix Time Series"
                }
            ]
        }
    ]
}

Sample: Analytic Adder with Multi-Dimensional Timeseries Ports

The following is a sample JSON input.

{
    "internalRecords": [],
    "records": [],
    "timeSeriesRecords": [
        {
            "name": "time_series",
            "timestamps": [
                "2016-02-17T18:27:49.601",
                "2016-02-17T18:27:49.602",
                "2016-02-17T18:27:49.603",
                "2016-03-17T18:27:49.601",
                "2016-03-17T18:27:49.602",
                "2016-03-17T18:27:49.603"
            ],
            "data": [
                {
                    "type": "DOUBLE",
                    "name": "temperature",
                    "data": [
                        1.0,
                        2.0,
                        3.0,
                        5.0,
                        6.0,
                        7.0
                    ],
                    "arraySizes": [
                        2,
                        3
                    ]
                },
                {
                    "type": "DOUBLE",
                    "name": "vibration",
                    "data": [
                        100.0,
                        200.0,
                        300.0,
                        500.0,
                        600.0,
                        700.0
                    ],
                    "arraySizes": [
                        2,
                        3
                    ]
                }
            ]
        }
    ]
}

The following is a sample analytic output.

{
    "internalRecords": [],
    "records": [],
    "timeSeriesRecords": [
        {
            "name": "time_series",
            "timestamps": [
                "2016-02-17T18:27:49.601",
                "2016-02-17T18:27:49.602",
                "2016-02-17T18:27:49.603",
                "2016-03-17T18:27:49.601",
                "2016-03-17T18:27:49.602",
                "2016-03-17T18:27:49.603"
            ],
            "data": [
                {
                    "type": "DOUBLE",
                    "name": "results",
                    "data": [
                        101.0,
                        202.0,
                        303.0,
                        505.0,
                        606.0,
                        707.0
                    ],
                    "arraySizes": [
                        2,
                        3
                    ]
                }
            ]
        }
    ]
}

The following is a sample descriptive analytic template.

{
    "name": "TimeseriesAdder",
    "description": "",
    "packageName": "",
    "codeLanguage": "JAVA",
    "version": "1.0.0",
    "author": "Predix Analytics team",
    "inputDataPortDefinitions": [
        {
            "name": "time_series",
            "description": "",
            "dataType": "TimeSeries",
            "valueRequired": false,
            "variable": false,
            "arrayDimensions": 0
        },
        {
            "timeSeriesName": "time_series",
            "name": "temperature",
            "description": "",
            "dataType": "Double",
            "valueRequired": true,
            "variable": false,
            "arrayDimensions": 2
        },
        {
            "timeSeriesName": "time_series",
            "name": "vibration",
            "description": "",
            "dataType": "Double",
            "valueRequired": true,
            "variable": false,
            "arrayDimensions": 2
        }
    ],
    "outputDataPortDefinitions": [
        {
            "name": "time_series",
            "description": "",
            "dataType": "TimeSeries",
            "valueRequired": false,
            "variable": false,
            "arrayDimensions": 0
        },
        {
            "timeSeriesName": "time_series",
            "name": "results",
            "description": "",
            "dataType": "Double",
            "valueRequired": false,
            "variable": false,
            "arrayDimensions": 2
        }
    ]
}

The following is a sample port-to-field map.

{
    "analyticName": "timeseries-adder",
    "analyticVersion": "1.0",
    "orchestrationStepId": "sid-10001",
    "iterations": [
        {
            "inputMaps": [
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.temperature[0]",
                    "fieldId": "temperature.previous",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.temperature[1]",
                    "fieldId": "temperature.current",
                    "queryCriteria": {
                        "start": 1458239269601,
                        "end": 1458239269603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.vibration[0]",
                    "fieldId": "vibration.previous",
                    "queryCriteria": {
                        "start": 1455733669601,
                        "end": 1455733669603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "valueSourceType": "DATA_CONNECTOR",
                    "fullyQualifiedPortName": "time_series.vibration[1]",
                    "fieldId": "vibration.current",
                    "queryCriteria": {
                        "start": 1458239269601,
                        "end": 1458239269603
                    },
                    "required": true,
                    "dataSourceId": "Predix Time Series"
                }
            ],
            "outputMaps": [
                {
                    "fullyQualifiedPortName": "time_series.results[0]",
                    "fieldId": "results.previous",
                    "dataSourceId": "Predix Time Series"
                },
                {
                    "fullyQualifiedPortName": "time_series.results[1]",
                    "fieldId": "results.current",
                    "dataSourceId": "Predix Time Series"
                }
            ]
        }
    ]
}