イベントタイプ登録
イベントタイプXを読み取る文を配備するには、まずXを登録する必要があります。
未登録タイプ上の文はコンパイルされ、配備され、実行され、永遠にマッチしません。 緑のジョブ・緑のパイプライン・停止したアラームで、後で捕捉されるポイントがありません。そのため、配備時に名前を挙げて拒否します。
何を登録するか
| 項目 | ルール |
|---|---|
name | ^[A-Za-z_][A-Za-z0-9_]*$。文がFROM Xで書く名前と同一である必要があります |
fields[] | 最低1つ。 空リストは拒否 — 「選ぶものが何もない」 |
フィールドtype | スカラー5つSTRING・BOOLEAN・INT・LONG・DOUBLE、時刻TIMESTAMP、マップ5つMAP_STRING・MAP_BOOLEAN・MAP_INT・MAP_LONG・MAP_DOUBLE |
フィールドname | 同じパターン。event_timeは使用できず、重複も不可です |
event_time_field | 必須。デフォルト値なし。 リテラル@envelope、または宣言された**LONG**フィールド名(epoch ms) |
event_time_fieldにデフォルト値がないのは意図的ですイベント時刻を推測したタイプは、実行中に何もマッチしない文を生成します。
指定できるのは**LONGフィールドのみ**です(epoch ms)。TIMESTAMPはカラムにはなり得ますが、時刻基準の出所ではありません。
TIMESTAMPとMAP_*
スカラー5つだけだった時代には、プラットフォーム自身のイベントクラスが登録できませんでした — Point・PointMap・Alarm・AssetData・AssetEventがそれぞれ日付やマップメンバーを持っていたためです。エンジンが積めないのではなく、レジストリに名前がなかったのです。
MAP_*は値タイプを名前に含めます。
{ "name": "data_map", "type": "MAP_STRING" },
{ "name": "timestamp_map", "type": "MAP_LONG" }
1つの資産イベントが文字列マップとepochマップを両方持つことができます。1つにまとめてすべて文字列として読み取ると、epochが文字列になり、比較が辞書順に変わり、文はそのまま動きます。
- **キーは常に
STRING**です — JSONオブジェクトのキーに他の種類はありません。 - 値タイプはスカラー5つのうちの1つだけです。値が再びオブジェクトであるマップは、メンバー名を挙げて拒否されます。文字列にまとめると、文は比較はするものの意味のない値を見ることになります。
MAP_*は項目ごとに変換し、変換できない項目はキーを挙げて拒否します(timestamp_map[bad]) — カラム名だけ挙げても、50項目のうちどれかを特定できません。
TIMESTAMPは「瞬間」であり「壁時計」ではありませんプロジェクションが受け入れるTIMESTAMPの形は2つだけです — 数値(epoch ms)、およびその数値を格納した日付オブジェクトです。
ISO文字列は名前を挙げて拒否します。 その文字列は書き手側のデフォルトタイムゾーンでレンダリングされ、オフセットが付いていないため、読み手側でパースするとTaskManagerのタイムゾーンが適用されます。その差だけウィンドウがずれたまま、何も赤くなりません。
⚠ ワイヤー形状は変わっていません。フィールドは依然として{"name": …, "type": …}であり、スキーマバージョンもそのままです — 値タイプが「タイプ名の中」にあるためです。
API
| メソッド | パス | 動作 |
|---|---|---|
GET | /api/v1/event-types | 一覧、名前順 |
GET | /api/v1/event-types/{name} | 1件。なければ404 |
POST | /api/v1/event-types | 登録。名前が既にあれば409 |
PUT | /api/v1/event-types/{name}?redeploy=false | 修正。使用中の文があれば409、redeploy=trueなら同じ呼び出しで再配備 |
DELETE | /api/v1/event-types/{name} | 削除。使用中の文があれば409 |
# 등록
curl -fsS -X POST http://127.0.0.1:7400/api/v1/event-types \
-H "X-API-Key: ${PP_CEP_API_KEY}" -H 'Content-Type: application/json' \
-d '{
"name": "AlarmEvent",
"event_time_field": "occurred_at",
"fields": [
{ "name": "machineId", "type": "STRING" },
{ "name": "severity", "type": "INT" },
{ "name": "occurred_at","type": "LONG" }
]
}'
# 목록
curl -fsS -H "X-API-Key: ${PP_CEP_API_KEY}" http://127.0.0.1:7400/api/v1/event-types
# 스키마를 바꾸고 그 타입을 쓰는 문장까지 같은 호출에서 재배포
curl -fsS -X PUT "http://127.0.0.1:7400/api/v1/event-types/AlarmEvent?redeploy=true" \
-H "X-API-Key: ${PP_CEP_API_KEY}" -H 'Content-Type: application/json' -d @alarm-event.json
redeployのデフォルト値は**false**です。redeploy=trueで再配備中に1つでも失敗すると以前のスキーマに戻します。- パスの名前と本文の名前が異なる場合は400です — このエンドポイントはタイプ1つを変更するものであり、改名するものではありません。
- レジストリがまだ初期化されていない場合は503
Event type registry is not initialized.です。空リストを返さない理由は、それが「登録されたタイプがない」と読まれ、そうするとエンジンがすべての文を拒否するためです。
ストレージ
PostgreSQL datalake DBのcep_event_typeテーブルです。
CREATE TABLE IF NOT EXISTS cep_event_type (
name TEXT NOT NULL,
event_time_field TEXT NOT NULL,
fields_json TEXT NOT NULL,
version BIGINT NOT NULL,
updated_at_ms BIGINT NOT NULL,
updated_by TEXT,
CONSTRAINT cep_event_type_pkey PRIMARY KEY (name)
);
テーブルはCEP起動時に自ら作成します。 自らが所有するテーブルセット(cep_event_type・cep_statement・cep_api_key)を自らマイグレーションします — すべて「存在すればそのまま」の形式で、削除する構文がないため、既に値が入っているインストールにもそのまま適用されます。
読み取りに失敗すると、空の結果ではなく例外です。空の結果を返すと、正常に登録されたタイプに対してエンジンがすべての文を拒否し、その拒否がオペレーターがタイプミスをしたかのようにそのタイプを名指しすることになります。
テーブル全体がないとレジストリがその場で失敗し、その文が未登録タイプのように拒否されます — オペレーターがタイプミスを探すことになります。
そのため/api/healthがスキーマを別途確認します。 ないテーブルを名前を挙げてDEGRADEDで報告します。起動順序によりDBが遅い場合は、自ら回復します。
タイプがエンジンのストリームになる経路
登録したタイプ1つがバックエンドの入力ストリーム1つになります — ストリーム名 = イベントタイプ名です。
タイプをエンジンタイプに移す箇所は1か所のみで、その分岐にはデフォルトの分岐がありません — タイプが1つ増えるとコンパイルが壊れるようにしてあります。静かに「未知のタイプ」に落ちると、カラム1つが意味のない値になります。
epochミリ秒はタイムゾーンのない瞬間です。タイムゾーンのない「壁時計」タイプに瞬間を入れると、タイムゾーンを選びながらも言及しないことになり、他の時刻カラムと比較するたびにセッションオフセット分だけ静かにずれます。
ペイロードをJSONとして読み取り、登録されたスキーマにプロジェクションします。プロデューサーのJavaクラスがエンジン側に1つもロードされないため、**新しいイベントタイプは「テーブルの1行」**です。
- タイプが異なる値は名前を挙げて拒否します。
3.5をINTに入れると、切り詰めずに拒否します。 - 存在しないフィールドはnullにします — 意図された非対称性です。
未登録タイプの拒否メッセージ
配備リクエスト(POST /api/v1/eql/deploy、400、EQL deploy failed: プレフィックス):
event type(s) not registered: X, Y. A statement over an unregistered type deploys, runs
and matches nothing, so it is refused here. Registered types are: A, B
レジストリが空の場合、最後の文はNo event type is registered at all.です。
エンジン側:
event type [X] is not registered. Registered types are: A, B, C
event type [X] is not registered - no event type is registered at all. Register it before deploying a statement that reads it
event type [X] has no input table in this environment after <how> - tables present: [...]
コントロールプレーン:
the engine refused this rule and will refuse it again: <위 메시지>
検査タイミング — 2つ、両方ともジョブ提出「前」
| タイミング | なぜそこ |
|---|---|
配備リクエスト(/api/v1/eql/deploy) | 未登録タイプ上の文は後で捕捉されるポイントがないため、ここで名前を挙げて捕捉します |
| エンジン提出 | クエリがコンパイルされる前であり、ジョブが実行された後ではありません |
レジストリを読み取れない、または文をパースできない場合は、配備を許可しつつ成功メッセージにその理由を添えます。 「『配備された』と読むオペレーターが『イベントタイプは検査されていない』も同時に読む」という意味です。