Registrierung von Ereignistypen
Um eine Anweisung bereitzustellen, die Ereignistypen X liest, müssen Sie zuerst X registrieren.
Anweisungen über nicht registrierten Typen werden kompiliert, bereitgestellt, laufen und matchen nie wieder. Grüner Job · grüne Pipeline · stehender Alarm und kein späterer Punkt, an dem sie erfasst wird. Deshalb wird bei der Bereitstellung mit Namen abgelehnt.
Was wird registriert
| Punkt | Regel |
|---|---|
name | ^[A-Za-z_][A-Za-z0-9_]*$. Muss identisch mit dem Namen sein, den die Anweisung über FROM X verwendet |
fields[] | Mindestens eine. Leere Liste wird abgelehnt — «es gibt nichts auszuwählen» |
Feld type | Skalar fünf STRING · BOOLEAN · INT · LONG · DOUBLE, Zeit TIMESTAMP, Map fünf MAP_STRING · MAP_BOOLEAN · MAP_INT · MAP_LONG · MAP_DOUBLE |
Feld name | Gleiches Muster. event_time ist nicht zulässig, auch keine Duplikate |
event_time_field | Pflichtfeld. Kein Standardwert. Entweder ein Literal @envelope oder ein deklarierter LONG Feldname (Epoch ms) |
event_time_field keinen Standardwert hatEin Typ, der die Ereigniszeit schätzt, erzeugt eine Anweisung, die läuft und nichts matcht.
Worauf verwiesen werden kann, ist nur das LONG-Feld (Epoch ms). TIMESTAMP kann zwar eine Spalte sein, ist aber keine Quelle für den Zeitbezug.
TIMESTAMP und MAP_*
Zu Zeiten, als es nur fünf Skalare gab, konnten die eigenen Ereignisklassen der Plattform nicht registriert werden — weil Point · PointMap · Alarm · AssetData · AssetEvent jeweils Datums- oder Map-Mitglieder enthielten. Nicht, dass die Engine sie nicht tragen konnte, sondern es gab einfach keinen Namen im Register.
MAP_* nimmt den Werttyp in den Namen auf.
{ "name": "data_map", "type": "MAP_STRING" },
{ "name": "timestamp_map", "type": "MAP_LONG" }
Ein Anlagenereignis kann sowohl eine String-Map als auch eine Epoch-Map enthalten. Wenn man beides zu einer einzigen String-Map zusammenfasst, wird Epoch zum String, der Vergleich wird lexikografisch, und die Anweisung läuft trotzdem.
- Der Schlüssel ist immer
STRING— JSON-Objektschlüssel haben keine anderen Typen. - Der Werttyp ist nur einer der fünf Skalare. Eine Map, deren Wert wieder ein Objekt ist, wird mit dem Namen des Mitglieds abgelehnt. Wenn man sie zu Strings zusammenfasst, vergleicht die Anweisung zwar, sieht aber Werte, die nichts bedeuten.
MAP_*konvertiert pro Eintrag, und nicht konvertierbare Einträge werden mit dem Schlüssel abgelehnt (timestamp_map[bad]) — nur den Spaltennamen zu nennen reicht nicht, um zu wissen, welcher der fünfzig Einträge gemeint ist.
TIMESTAMP ist ein «Moment», keine «Wanduhr»Die TIMESTAMP-Formen, die die Projektion akzeptiert, sind nur zwei — eine Zahl (Epoch ms) und ein Datumsobjekt, das diese Zahl enthält.
ISO-Strings werden mit Namen abgelehnt. Dieser String ist in der Standardzeitzone des Schreibers gerendert und trägt keinen Offset; wenn ihn die lesende Seite parst, wird die Zeitzone des TaskManagers angewendet. Um genau diese Differenz verschiebt sich das Fenster, und nichts wird rot.
⚠ Die Drahtform hat sich nicht geändert. Das Feld bleibt {"name": …, "type": …}, und die Schema-Version ist unverändert — weil der Werttyp «im Typnamen» steht.
API
| Methode | Pfad | Aktion |
|---|---|---|
GET | /api/v1/event-types | Auflisten, alphabetisch |
GET | /api/v1/event-types/{name} | Einzeln. 404, wenn nicht vorhanden |
POST | /api/v1/event-types | Registrieren. 409, wenn der Name bereits existiert |
PUT | /api/v1/event-types/{name}?redeploy=false | Ändern. 409, wenn eine Anweisung darauf schreibt. Bei redeploy=true erfolgt die erneute Bereitstellung im selben Aufruf |
DELETE | /api/v1/event-types/{name} | Löschen. 409, wenn eine Anweisung darauf schreibt. |
# 등록
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
- Der Standardwert von
redeployistfalse. - Wenn bei der erneuten Bereitstellung über
redeploy=trueauch nur einer fehlschlägt, wird auf das vorherige Schema zurückgerollt. - Wenn der Name im Pfad und der Name im Body nicht übereinstimmen, ergibt das 400 — dieser Endpunkt ändert einen Typ, benennt ihn nicht um.
- Wenn das Register noch nicht initialisiert ist, ergibt das 503
Event type registry is not initialized.. Der Grund, warum keine leere Liste zurückgegeben wird: Das würde als «keine registrierten Typen» gelesen, und dann würde die Engine alle Anweisungen ablehnen.
Speicher
Die PostgreSQL datalake-DB, Tabelle 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)
);
Die Tabelle erstellt sich selbst, wenn die CEP startet. Sie migriert ihren eigenen Tabellensatz (cep_event_type · cep_statement · cep_api_key) selbst — alles im Stil «wenn vorhanden, unverändert lassen», ohne Löschbefehle, und gilt daher auch für Installationen, die bereits Daten enthalten.
Wenn das Lesen fehlschlägt, ist das eine Ausnahme, nicht ein leeres Ergebnis. Ein leeres Ergebnis würde die Engine dazu bringen, alle Anweisungen für einen korrekt registrierten Typ abzulehnen, und diese Ablehnung würde den Typ wie einen Tippfehler des Bedieners erscheinen lassen.
Wenn die Tabelle komplett fehlt, schlägt das Register an Ort und Stelle fehl, und die zugehörigen Anweisungen werden wie nicht registrierte Typen abgelehnt — sodass der Bediener nach einem Tippfehler sucht.
Deshalb prüft /api/health das Schema separat. Fehlende Tabellen werden mit Namen bei DEGRADED gemeldet. Falls die DB aufgrund der Startreihenfolge später kommt, erholt sich das System von selbst.
Der Weg, wie ein Typ zum Stream der Engine wird
Jeder registrierte Typ wird zu einem Eingabestream des Backends — Stream-Name = Ereignistyp-Name.
Die Stelle, an der ein Typ in einen Engine-Typ überführt wird, gibt es nur eine, und dieser Verzweigungspunkt hat keinen Standardzweig — wenn ein Typ hinzukommt, bricht die Kompilierung absichtlich. Wenn er still in die Kategorie «unbekannter Typ» fiele, würde eine Spalte zu einem bedeutungslosen Wert.
Epoch-Millisekunden sind ein Moment ohne Zeitzone. Wenn man einen Moment in einen Typ «Wanduhr» ohne Zeitzone einfügt, ist das, als würde man eine Zeitzone wählen, aber nicht benennen — und bei jedem Vergleich mit einer anderen Zeitspalte verschiebt es sich still um den Sitzungs-Offset.
Die Payload wird als JSON gelesen und auf das registrierte Schema projiziert. Da keine Java-Klasse des Produzenten auf der Engine-Seite geladen wird, ist ein neuer Ereignistyp «eine Zeile in der Tabelle».
- Werte falschen Typs werden mit Namen abgelehnt. Wenn man
3.5inINTeinfügt, wird nicht gekürzt, sondern abgelehnt. - Fehlende Felder werden als null gelassen — das ist beabsichtigte Asymmetrie.
Ablehnungsmeldung für nicht registrierte Typen
Bereitstellungsanfrage (POST /api/v1/eql/deploy, 400, EQL deploy failed: Präfix):
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
Wenn das Register leer ist, lautet die letzte Anweisung No event type is registered at all..
Auf der Engine-Seite:
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: [...]
Kontroll-Ebene:
the engine refused this rule and will refuse it again: <위 메시지>
Prüfzeitpunkte — zwei, beide vor der Job-Einreichung
| Zeitpunkt | Warum dort |
|---|---|
Bereitstellungsanfrage (/api/v1/eql/deploy) | Anweisungen über nicht registrierte Typen haben keinen späteren Erfassungspunkt, also werden sie hier mit Namen erfasst |
| Engine-Einreichung | Bevor die Abfrage kompiliert wird, nicht nachdem der Job läuft |
Wenn das Register nicht lesbar ist oder die Anweisung nicht geparst werden kann, wird die Bereitstellung zugelassen, aber der Grund wird der Erfolgsmeldung hinzugefügt. Das bedeutet: «Der Bediener, der ‚bereitgestellt‘ liest, liest auch ‚Ereignistyp wurde nicht geprüft‘.»
Verwandte Dokumentation
- EQL-Sprache
- Grenzen und Ablehnungsstrings
- CEP-Client — auch im SDK gibt es einen Einstiegspunkt für die Ereignistyp-Registrierung