在 Whistle 中編寫指令碼

本指南提供撰寫剖析器 Whistle 指令碼的一般指引。如要進一步瞭解 Whistle 語法和可用函式,請參閱 Whistle 參考資料

撰寫哨聲腳本

開始編寫 Whistle 指令碼前,建議您先:

  1. 瞭解剖析器訂閱的來源訊息類別中訊息的結構定義。 為避免對應失敗,導致訊息進入無效信件佇列,Whistle 指令碼必須能夠對應所有傳入訊息。如果訊息結構定義因訊息而異,Whistle 指令碼就必須處理這些差異。

    瞭解來源訊息結構定義有助於掌握來源訊息中的欄位及其資料類型,進而決定如何將來源訊息中的欄位對應至目標類型結構定義。瞭解資料的語意也很重要,這樣才能有效決定來源訊息的哪些部分應對應至目標架構中的屬性。

    舉例來說,瞭解屬性值變更的頻率,有助於判斷應將哪些資料對應為內嵌中繼資料,哪些資料應對應為雲端中繼資料。請參閱「建立來源訊息類別模型」和「建立資料模型」一節。

  2. 瞭解為剖析器定義的類型版本結構定義。剖析器中的 Whistle 指令碼會將來源訊息對應至為剖析器定義的類型版本結構定義。如要瞭解如何建構符合類型版本需求的 Proto 記錄,請查詢類型規格。請特別注意 data 欄位的結構定義,以及任何中繼資料值區關聯。請特別注意是否有任何中繼資料儲存區關聯標示為 required: true。如果您打算依值查詢中繼資料執行個體,請記下相關聯的 bucket 的結構定義。

  3. 編寫 Whistle 指令碼。Whistle 指令碼會執行實際的來源到目標轉換作業。來源訊息會載入名為 $root 的輸入內容。如要瞭解語言和可用函式,請參閱 Whistle 參考資料。另請參閱本節的其他指南,例如如何將記錄連結至中繼資料執行個體

最佳做法

本節概述撰寫 Whistle 指令碼的最佳做法。

存取訊息屬性時執行空值檢查

建議您在存取訊息屬性時檢查空值,因為屬性可能未定義。

//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
    }
  }
]