跳到主要内容

事件类型注册

要部署读取事件类型 X 的语句,必须首先注册 X。

不注册,语句就会“悄无声息”地不匹配任何内容

针对未注册类型的语句会被编译、部署、运行,然后永远不匹配任何内容。绿色的作业 · 绿色的管道 · 静止的报警,之后没有任何地方可以捕捉到它。因此,在部署时会明确指出名称并拒绝。

要注册什么​

项目规则
name^[A-Za-z_][A-Za-z0-9_]*$。必须与语句使用 FROM X 写入的名称完全相同
fields[]至少一个。 空列表会被拒绝 — “没有什么可选的”
字段 type五个标量 STRING · BOOLEAN · INT · LONG · DOUBLE,时间 TIMESTAMP,五个映射 MAP_STRING · MAP_BOOLEAN · MAP_INT · MAP_LONG · MAP_DOUBLE
字段 name相同的模式。event_time 不可用,也不能重复
event_time_field必填。没有默认值。 可以是字面量 @envelope,或者声明的 LONG 字段名(epoch 毫秒)
event_time_field 没有默认值是有意为之

猜测事件时间的类型会产生运行时什么也不匹配的语句。

可以指向的只有 LONG 字段(epoch 毫秒)。TIMESTAMP 可以是列,但不是时间基准的来源。

TIMESTAMP 和 MAP_*​

在只有五个标量的时代,平台自身的事件类无法被注册 — 因为 Point · PointMap · Alarm · AssetData · AssetEvent 各自都带有日期或映射成员。不是引擎无法加载,而是注册表中没有它们的名称。

MAP_* 将值类型放入名称中。

{ "name": "data_map", "type": "MAP_STRING" },
{ "name": "timestamp_map", "type": "MAP_LONG" }

一个资产事件可以同时持有字符串映射和 epoch 映射。如果将它们合并成一个并全部读为字符串,epoch 就会变成字符串,导致比较变成字典序比较,语句就这样运行了。

  • 键始终是 STRING — JSON 对象的键没有其他类型。
  • 值类型只能是五个标量之一。 值为对象类型的映射会被明确指出成员名称并拒绝。如果强行转换为字符串,语句虽然能进行比较,但看到的是没有意义的值。
  • MAP_* 会逐项转换,无法转换的项会明确指出键并拒绝(timestamp_map[bad])— 只指出列名无法确定是五十个项目中的哪一个。
TIMESTAMP 是“瞬间”,不是“挂钟时间”

投影接受 TIMESTAMP 的形式只有两种 — 数字(epoch 毫秒),以及包含该数字的日期对象。

ISO 字符串会被明确指出名称并拒绝。 该字符串是按照写入方的默认时区渲染的,且没有附加偏移量,读取方解析时会应用 TaskManager 的时区。这个差异会导致窗口错位,然后什么也不会变红。

⚠ 线上格式没有改变。字段仍然是 {"name": …, "type": …},schema 版本也保持不变 — 因为值类型在“类型名称内”。

API​

方法路径操作
GET/api/v1/event-types列表,按名称顺序
GET/api/v1/event-types/{name}单个。不存在则返回 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 重新部署时,只要有一个失败,就会回滚到之前的 schema。
  • 如果路径中的名称与请求体中的名称不一致,返回 400 — 此端点用于修改一个类型,而不是重命名它。
  • 如果注册表尚未初始化,返回 503 Event type registry is not initialized.。不返回空列表的原因是,它会被解读为“没有已注册的类型”,然后引擎会拒绝所有语句。

存储​

PostgreSQL datalake 数据库中的 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 会单独检查 schema。 如果表缺失,会明确指出名称并通过 DEGRADED 报告。如果是由于启动顺序导致数据库延迟,则会自行恢复。

类型成为引擎流的路径​

每个已注册的类型都会成为后端的一个输入流 — 流名称 = 事件类型名称。

将类型转换为引擎类型的位置只有一个,且该分支没有默认路径 — 增加一个类型会导致编译失败。如果静默地落入“未知类型”,一个列就会变成无意义的值。

时间视为“瞬间”

epoch 毫秒是没有时区的瞬间。将瞬间放入没有时区的“挂钟时间”类型,等于选择了一个时区却不说明,每次与其他时间列比较时,都会按会话偏移量悄悄错位。

无需部署事件类

将载荷读取为 JSON 并投影到已注册的 schema。由于生产者的 Java 类不会加载到引擎侧,新事件类型就是“表中的一行”。

  • 类型错误的值会被明确指出名称并拒绝。将 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: <위 메시지>

检查时机 — 两个,都在作业提交“之前”​

时机为什么在那里
部署请求 (/api/v1/eql/deploy)针对未注册类型的语句没有后续可以捕捉到它的地方,因此在这里明确指出并捕获
引擎提交在查询编译之前,而不是作业运行之后
部署门“响亮地打开”

如果无法读取注册表或无法解析语句,部署会被允许,但成功消息中会附加原因。 这意味着“读到‘已部署’的操作员也会读到‘事件类型未被检查’”。

相关文档​