在 Whistle 中编写脚本

本指南提供了有关为解析器编写 Whistle 脚本的一般指导。 如需详细了解 Whistle 语法和可用函数,请参阅 Whistle 参考文档

口哨脚本编写

在开始编写 Whistle 脚本之前,建议您:

  1. 了解解析器订阅的源消息类中消息的架构。 为防止映射失败,从而导致消息进入死信队列,Whistle 脚本必须能够映射所有传入的消息。如果消息架构因消息而异,您的 Whistle 脚本需要处理这些差异。

    了解源消息架构有助于您了解源消息中存在哪些字段以及这些字段的数据类型,以便您决定如何将源消息中的字段映射到目标类型架构。 了解数据的语义也很重要,这样您才能有效地决定应将源消息的哪些部分映射到目标架构中的属性。

    例如,了解属性值更改的频率有助于您决定应将哪些数据映射为嵌入式元数据,哪些数据映射为云元数据。请参阅有关对源消息类进行建模对数据进行建模的部分。

  2. 了解为解析器定义的类型版本的架构。解析器中的 Whistle 脚本会将源消息映射到为解析器定义的类型版本架构。如需了解如何构建符合类型版本要求的 proto 记录,您应查找类型规范。您应特别注意 data 字段的架构,以及任何元数据存储桶关联。请务必注意,如果任何元数据桶关联被标记为 required: true,则表示存在问题。如果您打算按值查找元数据实例,则应记下关联的存储分区的架构。

  3. 编写 Whistle 脚本。Whistle 脚本执行实际的源到目标转换。源消息会加载到名为 $root 的输入中。如需简要了解该语言和可用函数,请参阅 Whistle 参考文档。另请参阅本部分中的其他指南,例如如何将记录关联到元数据实例

最佳做法

本部分概述了编写 Whistle 脚本的最佳实践。

在访问消息属性时执行 null 检查

建议在访问消息属性时检查是否为 null,因为该属性可能未定义。

//Add metadata from source bucket if metadata.source attribute is present
if(isNotNil(input.metadata) and isNotNil(input.metadata.source)) then {
{
    var metadataArray[]: {
        bucketReference: {
            bucketName: "source";
            version: 1;
        };
            naturalKey: input.metadata.source;
        }
    }
}

示例

以下部分展示了使用 Whistle 进行基本操作的一些示例。

简单的 Whistle 映射

假设有以下来源消息...

{
  "sensor": "rotation-speed-sensor",
  "machine": "m-234",
  "timestamp": "1687973092857",
  "value": 1200
}

以及以下 Whistle 脚本:

package mde

[
    {
        tagName: $root.machine + " - " + $root.sensor;
        data: {
            numeric: $root.value;
        };
        timestamps: {
            eventTimestamp: $root.timestamp;
        }
    }
]

解析器将生成以下 proto 记录输出:

[
  {
    "tagName": "m-234-rotation-speed-sensor",
    "data": {
      "numeric": 1200
    },
    "timestamps": {
      "eventTimestamp": "1687973092857"
    }
  }
]

使用函数进行简单的 Whistle 映射

假设有以下来源消息:

{
  "sensor": "rotation-speed-sensor",
  "machine": "m-234",
  "timestamp": "1687973092857",
  "value": 1200
}

以及以下 Whistle 脚本:

package mde

[
    {
        tagName: getTagName($root);
        data: getValue($root);
        timestamps: getTimestamp($root)
    }
]

def getTagName(input) {
    input.machine + "-" + input.sensor;
}

def getTimestamp(input) {
    eventTimestamp: input.timestamp;
}

def getValue(input) {
    numeric: input.value;
}

解析器将生成以下 proto 记录输出:

[
  {
    "tagName": "m-234-rotation-speed-sensor",
    "data": {
      "numeric": 1200
    },
    "timestamps": {
      "eventTimestamp": "1687973092857"
    }
  }
]

从解析器 1 发出多个 Proto 记录

假设有以下来源消息:

{
  "tag": "plc-34",
  "machine": "controller",
  "timestamp": "1687973092857",
  "values": [200, 499]
}

以及以下 Whistle 脚本:

package mde

var valueLen: listLen($root.values);
var indexes: range(0, valueLen);

[
    getProtoRecords($root.values[], indexes[], $root)
]

def getProtoRecords(value, index, input) {
        tagName: input.machine + "-" + input.tag + "-" + index;
        data: {
            numeric: value;
        };
        timestamps: {
            eventTimestamp: input.timestamp;
        };
}

解析器将生成以下 proto 记录输出:

[
  {
    "tagName": "controller-plc-34-0",
    "data": {
      "value": 200.0
    },
    "timestamps": {
      "eventTimestamp": "1687973092857"
    }
  },
  {
    "tagName": "controller-plc-34-1",
    "data": {
      "value": 499.0
    },
    "timestamps": {
      "eventTimestamp": "1687973092857"
    }
  }
]

从解析器 2 发出多个 Proto 记录

假设有以下来源消息:

{
  "machine": "controller",
  "timestamp": "1687973092857",
  "sensors": [
    {
      "tag": "plc-34",
      "value": 200
    },
    {
      "tag": "plc-35",
      "value": 499
    }
  ]
}

以及以下 Whistle 脚本:

package mde

[$$
    getProtoRecords($root.sensors[], $root)
]

def getProtoRecords(sensor, input) {
        tagName: input.machine + "-" + sensor.tag;
        data: {
            numeric: sensor.value;
        };
        timestamps: {
            eventTimestamp: input.timestamp;
        };
}

解析器将生成以下 proto 记录输出:

[
  {
    "tagName": "controller-plc-34",
    "timestamps": {
      "eventTimestamp": "1687973092857"
    },
    "data": {
      "numeric": 200
    }
  },
  {
    "tagName": "controller-plc-35",
    "timestamps": {
      "eventTimestamp": "1687973092857"
    },
    "data": {
      "numeric": 499
    }
  }
]