カスタムフラグメント
Things Cloud APIを使用すると、データを自由に構築できます。Apama EPLでは、params
にエントリを追加することで行われ、これらはdictionary<string, any>
型となります。com.apama.cumulocityパッケージの各Things Cloudイベント(Alarm、Event、Measurement、Operationなど)にはparams
フィールドがあり、これはフラグメントまたは任意のフィールドに変換されます。したがって、イベントを受信するとき、コードはparams
フィールドのエントリを検索する必要があります。イベントを送信するときは、イベントタイプを定義するか、またはdictionary <string、any>
タイプを使用します。イベントを受信する場合、EPLの型は dictionary <any、any>
になります。EPLは強く型付けされているため、フラグメントのないイベントを作成する場合は、new dictionary<string, any>
を使用する必要があることに注意してください。ディクショナリーリテラルとインラインでエントリを提供している場合、EPLは最初のキーバリューペアの型に基づいて型を決定します。したがって、 dictionary<string, any>
の場合、<any>
キャスト演算子を使用して、最初の値を any
タイプにキャストします:
send Event(..., new dictionary<string,any>) to Event.SEND_CHANNEL;
send Event(..., {"fragment":<any>"value"}) to Event.SEND_CHANNEL;
MeasurementValue型は、Measurement型のメジャーメント用に提供されています。MeasurementValueには、value
フィールドとunit
フィールド、および他のフラグメント用のparams
があります。
例 1:
send Measurement("", "c8y_TemperatureMeasurement", "12345", currentTime, {
"c8y_TemperatureMeasurement":{
"T1":MeasurementValue(1.0, "C", new dictionary<string,any>),
"T2":MeasurementValue(2.0, "C", new dictionary<string,any>),
"T3":MeasurementValue(3.0, "C", new dictionary<string,any>),
"T4":MeasurementValue(4.0, "C", new dictionary<string,any>),
"T5":MeasurementValue(5.0, "C", new dictionary<string,any>)
}
},
new dictionary<string,any>) to Measurement.SEND_CHANNEL;
これにより、次のJSON構造が作成されます:
{
"type": "c8y_TemperatureMeasurement",
"time": "...",
"source": {
"id": "12345"
},
"c8y_TemperatureMeasurement": {
"T1": {
"value": 1,
"unit": "C"
},
"T2": {
"value": 2,
"unit": "C"
},
"T3": {
"value": 3,
"unit": "C"
},
"T4": {
"value": 4,
"unit": "C"
},
"T5": {
"value": 5,
"unit": "C"
},
}
}
メジャーメントフラグメント
メジャーメントは、個々のメジャーメントフラグメントに分割できます。これは、メジャーメントに存在するフラグメントとシリーズごとに実行できます。メジャーメントフラグメント詳細については、コンセプトガイドのThings Cloudのドメインモデルを参照してください。
メジャーメントフラグメントまたはシリーズに基づくフィルタリングが必要な場合は、Measurement
イベントをリッスンしてmeasurements
ディクショナリー内を調べる代わりに、com.apama.cumulocity.MeasurementFragment
型のイベントをリッスンします。詳細については、Apamaドキュメントの Using measurement fragments を参照してください。
リスナー
受信するイベントのみがステートメントのトリガーとなるわけではありません。次のセクションではリスナーを組み合わせる方法について説明します。詳細については、Apamaドキュメント内の Defining Event Listenersをご覧ください。
フィルター
フィルターを使用すると、他のトリガーの組み合わせまたはシーケンスでトリガーさせることができます。例えば、次のようなトリガーがあるとします:
on all Event() as e { ... }
パターンにフィルターを追加することができます:
on all Event(type = "c8y_EntranceEvent") as e { ... }
複数のイベントをリッスンできます:
on Event() as e and Alarm() as a { ... }
これは、イベントとアラームのイベント受信時にトリガーされます。 それぞれの最初のイベントがキャプチャされます。
シーケンスでトリガーさせることもできます:
on all (Event() as e -> Alarm() as a) { ... }
これは、「アラームが後に続くイベント」のペアごとにトリガーされます。イベントを受信すると、それ以降のイベントのリッスンを停止し、代わりにアラームのリッスンを開始します。アラームが受信されると、イベントのリッスンが再び開始されます。
タイマー
時間に基づいてリスナーをトリガーすることもできます。例えば、5分(300秒)ごとに起動するなど、特定の間隔でトリガーすることができます:
on all wait(300.0) { ... }
または、Unix cron スケジュラーと同様の機能を使用して、1日の特定の時間にリスナーを起動できます:
// timer:at(minutes, hours, daysOfMonth, month, daysOfWeek, (optional) seconds)
// minutes: 0-59
// hours: 0-23
// daysOfMonth: 1-31
// month: 1-12
// daysOfWeek: 0 (Sunday) - 6 (Saturday)
// seconds: 0-59
on all at(*, *, *, *, *) {} // trigger every minute
on all at(*/10, *, *, *, *) {} // trigger every 10 minutes
on all at(0, 1, *, *, [1,3,5]) {} // trigger at 1am every monday, wednesday and friday
on all at(0, */2, (1-7), *, *) {} // trigger every 2 hours on every day in the first week of every month
タイマーパターンを他のパターンと組み合わせることもできます。たとえば、別のイベントの後、特定の時間内にイベントがあったかどうかを確認できます:
on Event() -> wait(600.0) and not Alarm() { ... }
これは、イベントがあり、10分(600秒)以内にアラームがない場合にトリガーされます。not で指定されるイベントが発生した場合、リスナーが終了することに注意してください。
テナントオプションを使用すると、on all at
タイマーに使用するタイムゾーンを設定できます。テナントオプションを設定するには、カテゴリにmicroservice.runtime
を、 キーにtimezone
を指定します。
例:
{
"category" : "microservice.runtime",
"key" : "timezone",
"value" : "Europe/Warsaw"
}
また、Apamaドキュメントのサポートされているタイムゾーンも参照してください。
ストリーム - ウィンドウ
ストリームを使用すると、イベントのウィンドウを複数操作できます。ストリームはon
の代わりにfrom
キーワードを使用し、操作するウィンドウを定義し、集計を使用してそのウィンドウから出力を選択します。ウィンドウは2つの方法で制限できます:
-
一定期間のウィンドウ -
within
キーワードを使用します。from m in all Measurement(type="c8y_TemperatureMeasurement") within 3600.0 select avg(m.measurements ["c8y_TemperatureMeasurement"]["T"].value) as avgValue { }
-
一定量のイベントを持つウィンドウ -
retain
キーワードを使用します。from m in all Measurement(type="c8y_TemperatureMeasurement") retain 100 select avg(m.measurements["c8y_TemperatureMeasurement"]["T"].value) as avgValue { }
ストリーム - 定期的な出力
ストリームは、every
指定子を使用して、評価する頻度を制御することもできます。
// will output the last measurement arrived every 1 minute
from m in all Measurement(type="c8y_TemperatureMeasurement") within 60.0 every 60.0 select last(m.measurements["c8y_TemperatureMeasurement"]["T"].value) as lastValue { }
// will output the first of every 20 measurements arriving
from m in all Measurement(type="c8y_TemperatureMeasurement") retain 20 every 20 select first(m.measurements["c8y_TemperatureMeasurement"]["T"].value) as firstValue { }
// will output the average of all 20 measurements after the 20th arrived
from m in all Measurement(type="c8y_TemperatureMeasurement") retain 20 every 20 select avg(m.measurements["c8y_TemperatureMeasurement"]["T"].value) as avgValue { }
Apama ドキュメントの built-in aggregate functions をご覧ください。
独自のイベント型の作成
事前定義されたイベント型に加えて、独自のイベント型を定義できます。これらは、同じモジュールの他の部分をトリガーするイベントの発生パターンを検出するのに役立ちます。
event MyEvent {
Measurement m1;
Measurement m2;
}
...
on Measurement() as m1 -> Measurement() as m2 {
route MyEvent(m1, m2);
}
独自アクションの作成
通常、次の例に示すように、(Javaの関数によく似た)アクションを使用してモニターを構成します。
指定された重大度を上げる:
action upgradeSeverity(string old) returns string {
if old = "WARNING" { return "MINOR"; }
if old = "MINOR" { return "MAJOR"; }
if old = "MAJOR" { return "CRITICAL"; }
return old;
}
2つの地理座標間の距離を計算する:
action distance(float lat1, float lon1, float lat2, float lon2) returns float {
float R := 6371000.0;
float toRad := float.PI / 180.0;
float lat1Rad := lat1 * toRad;
float lat2Rad := lat2 * toRad;
float deltaLatRad := (lat2-lat1) * toRad;
float deltaLonRad := (lat2-lat1) * toRad;
float a := (deltaLatRad/2.0).sin().pow(2.0) * lat1Rad.cos() * lat2Rad.cos() * (deltaLonRad/2.0).sin().pow(2.0);
float c := 2.0 * a.sqrt().atan2((1.0-a).sqrt());
return R * c;
}
変数
モジュールで変数を定義できます。
string myEmailText := "Hello World";
sequence<string> supportedOperationsList := ["c8y_Restart", "c8y_Relay"];
モニタースコープ変数を定義する場合(つまり、モニター内であるが、モニターのどのアクション内にも存在しない場合)、リスナーでのイベント共同割り当ての際、as
の代わりにコロン(:)を使用すると、リスナーで使用できます。
次の例では、10秒ごとに最新のイベントを記録します:
monitor MyMonitor {
// monitor scope:
Event e;
action onload() {
monitor.subscribe(Measurement.SUBSCRIBE_CHANNEL);
on all Event():e {}
on all wait(10.0) {
log e.toString();
}
}
}
リスナーが開始されると、すべてのローカル変数のコピーが取得されます。 次の例では、他のイベントが間に挟まれても、10秒遅れて各イベントを記録します。
monitor MyMonitor {
// monitor scope:
Event e;
action onload() {
monitor.subscribe(Measurement.SUBSCRIBE_CHANNEL);
on all Event():e {
on all wait(10.0) {
log e.toString();
}
}
}
}
モニターインスタンスとコンテキストの生成
1つのモニターで複数のデバイスを処理することは可能ですが(たとえば、ストリームでgroup by
とpartition by
を使用したり、他の状態のデバイスIDにキー入力されたディクショナリーを維持したり)異なるデバイスの処理を複数のモニターインスタンスに分割すると便利なケースがあります。
新しいモニターインスタンスは、 spawn
ステートメントを使用して作成できます。これにより、モニターのモニタースコープ変数のコピーが取得され、新しいモニターインスタンスで名前付きアクションが実行されます。新しいモニターにリスナーはコピーされません。また、新しいモニターインスタンスを生成するコンテキストを指定することもできます。異なるコンテキストを同時に実行でき、また、異なるモニターを相互に分離することもできます。コンテキストを構築するとき、コンテキストを識別する名前、およびコンテキストがパブリックであるかどうかを制御するブール値を指定します。つまり、デフォルトでThings Cloudのイベントを受信します(デフォルトチャネルに送信されます)。
このパターンは、多くの場合、unmatchedキーワードとともに使用され、そのコンテキスト内の他のリスナーと一致しないイベントを識別します。各モニターに個別のコンテキストを使用することにより、対象の振る舞いはそのモニターのスコープに限定されます。例えば:
monitor PerDeviceMeasurementTracker {
action onload() {
spawn factory to context("PerDeviceMeasurementTracker", true);
}
action factory() {
monitor.subscribe(Measurement.SUBSCRIBE_CHANNEL);
on all unmatched Measurement() as m {
spawn perDevice(m);
}
}
dictionary<string, Measurement> latestMeasurementByType; // measurements for this device
action perDevice(Measurement m) {
processMeasurement(m);
on all Measurement(source = m.source) as m {
processMeasurement(m);
}
}
action processMeasurement(Measurement m) {
latestMeasurementByType[m.type] := m;
}
}
ストリーミング分析アプリケーションのアクセス制御
デフォルトでは、ストリーミング分析アプリケーションからAnalytics BuilderおよびEPL Appsページにアクセスできます。 管理者は、異なるテナントまたは異なるユーザーに対してどのページを表示するかを制御したり、ホーム画面のカードの文言を変更したりすることができます(ストリーミング分析アプリケーションのホーム画面のカスタマイズも参照してください)。
どのページが利用可能かは、実行されているApama-ctrlマイクロサービスの種類によっても異なります。
- マイクロサービスが実行されていない場合は、マイクロサービスにアクセスできないことを示すエラーメッセージが表示され、スマートルールに関する情報が記載されたカードのみが表示されます。
- Apamaスマートルール専用マイクロサービスが実行されている場合、EPL Appsカードも Analytics Builderカードも表示されません (有効にすることもできません)。 この場合、スマートルールに関する情報が含まれるカードのみが表示されます。
- その他のApama-ctrlマイクロサービスでは、Analytics BuilderカードとEPL Appsカードの両方がデフォルトで表示されます。
テナント内に feature-disable-analyticsbuilder
もしくは feature-disable-eplapps
という名前の「機能アプリケーション」が存在する場合、テナント全体に対して該当の機能が無効になります。
これはテナント内で登録することも、親テナントからサブテナントに登録することもできます(親テナントから機能へのアクセスを制限する場合、サブテナントの管理者はこのアプリケーションの登録を解除できません)。
テナント内でこのような「機能アプリケーション」を作成するには、/application/applications
にPOSTリクエストを送信します(アプリケーションを作成する権限を持つ管理者が実施)。
Analytics Builderを無効にする場合:
{
"name":"feature-disable-analyticsbuilder",
"contextPath": "feature-disable-analyticsbuilder",
"type":"HOSTED",
"resourcesUrl":"/",
"manifest": {
"noAppSwitcher": true
},
"key":"feature-disable-analyticsbuilder-key"
}
EPL Appsを無効にする場合:
{
"name":"feature-disable-eplapps",
"contextPath": "feature-disable-eplapps",
"type":"HOSTED",
"resourcesUrl":"/",
"manifest": {
"noAppSwitcher": true
},
"key":"feature-disable-eplapps-key"
}
curl コマンドを使用して POST リクエストを送信することもできます。
Analytics Builderを無効にする場合:
curl --user username -X POST -H 'Content-Type: application/json' -d '{"name":"feature-disable-analyticsbuilder", "contextPath": "feature-disable-analyticsbuilder", "type":"HOSTED", "resourcesUrl":"/","manifest": {"noAppSwitcher": true},"key":"feature-disable-analyticsbuilder-key"}' -k https://{{hostname}}/application/applications/
EPL Appsを無効にする場合:
curl --user username -X POST -H 'Content-Type: application/json' -d '{"name":"feature-disable-eplapps", "contextPath": "feature-disable-eplapps", "type":"HOSTED", "resourcesUrl":"/", "manifest": {"noAppSwitcher": true},"key":"feature-disable-eplapps-key"}' -k https://{{hostname}}/application/applications/
デフォルトでは、すべてのユーザが同じページ一覧を見ることができます(上記の制限に従う)。
また、ROLE_ANALYTICSBUILDER_READ または ROLE_EPLAPPS_READ の権限を持つユーザーのみにページの閲覧を制限することもできます。
これらの権限は、ユーザーに直接割り当てる、もしくはグループを介して割り当てることができます(ユーザーガイドの 管理 > 権限の管理 も参照してください)。
これを有効にするには、テナントオプションのカテゴリ streaminganalytics
を設定し、applicationAccess
キーを “role” に設定します
(Things Cloud OpenAPI仕様のTenant APIも参照)。
curlコマンドの利用例:
curl --user username -X POST -H 'Content-Type: application/json' -d '{"category": "streaminganalytics", "key": "applicationAccess", "value": "role"}' -k https://mytenant/tenant/options
上記利用例のユーザー名は、「オプション管理」のADMIN権限を持つユーザー名に置き換える必要があります。
これは、ストリーミング分析アプリケーションのカードとページの可視性にのみ影響することに注意してください。 サポートされるRESTサービスは、「CEP 管理」の読み取りとおよび管理者権限のみを必要とします。
ストリーミング分析アプリケーションのホーム画面のカスタマイズ
ストリーミング分析アプリケーションのホーム画面に表示されるカードには、テナントごと、言語ごとにカスタマイズできるテキストとリンクが含まれています。これを行うには、URL /service/cep/apamacorrelator/EN/documentation.jsonからカスタマイズしたい言語のdocumentation.jsonファイルをダウンロードします(Things Cloudテナントのユーザで認証する必要があります)。URL内の “EN” をダウンロードしたいファイルの言語コードに置き換えてください。
documentation.jsonファイルには、ストリーミング分析アプリケーション全体のドキュメントリンクのURLと、ホーム画面に表示されるテキストが含まれています。これは、お客様の要件に合わせて変更することができます。
必要な変更をすべて行ったら、変更したコピーを含めた以下ファイル群をZIPファイルにパッケージします:
- files/support/cumulocity/EN/documentation.json
- cumulocity.json
cumulocity.jsonファイルには、以下の内容が含まれます:
{
"contextPath": "streaminganalytics-customization",
"availability": "MARKET",
"type": "HOSTED",
"name": "streaminganalytics-customization",
"key": "streaminganalytics-customization-key",
"noAppSwitcher": true
}
次に、管理アプリケーションを使用してZIPファイルをアップロードします。手順は、エコシステム > アプリケーション に進み、アプリケーションを追加 をクリックし、Webアプリケーションをアップロード を選択します。 詳細については、ユーザーガイドの管理 > アプリケーションの管理を参照してください。
変更を有効にするには、ブラウザのキャッシュクリアが必要な場合があります。
必要に応じて、1つのZIPファイルに複数の言語を含めることができます。また、必要に応じて親テナントからサブテナントに登録できます。
プラットフォームのアップグレード時は、documentation.jsonのソースファイルに変更がないか確認することをお勧めします。 このファイルの新しい項目は、デフォルト値でピックアップされます。