feat: 扩展心跳消息支持电力与空调设备数组字段
新增 Kafka 消息中 electricity[] 和 air_conditioner[] 数组字段支持,用于存储电力与空调设备明细数据。数据库表新增对应数组列并创建 GIN 索引优化查询性能,processor 实现数组字段校验与聚合转换逻辑。 主要变更: - Kafka 消息规范新增 electricity 和 air_conditioner 数组字段定义 - 数据库 heartbeat_events 表新增 14 个数组列并创建 4 个 GIN 索引 - processor 实现数组字段解析、校验及聚合转换逻辑 - 更新相关文档与测试用例,确保端到端功能完整
This commit is contained in:
14
openspec/changes/update-heartbeat-arrays-v3/proposal.md
Normal file
14
openspec/changes/update-heartbeat-arrays-v3/proposal.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Change: 扩展心跳消息与分区表以支持电力/空调数组(v3)
|
||||
|
||||
## Why
|
||||
当前心跳数据仅落库基础字段与 extra,无法按需查询与聚合“电力设备/空调设备”的细粒度状态;需要将数组结构拆列为数据库数组列,并对指定列提供数组元素索引。
|
||||
|
||||
## What Changes
|
||||
- **Kafka**:新增可选字段 `electricity[]`、`air_conditioner[]` 以及元素字段定义
|
||||
- **Processor**:新增数组字段类型校验与“按原始顺序聚合为列数组”的转换规则
|
||||
- **DB**:在 `heartbeat.heartbeat_events` 新增数组列,并为 `elec_address/air_address/state/model` 建立 GIN 索引(数组元素查询)
|
||||
- **Docs/Tests**:更新 producer 与 schema 文档;补充单元测试与冒烟验证
|
||||
|
||||
## Impact
|
||||
- Affected specs: `openspec/specs/kafka`, `openspec/specs/processor`, `openspec/specs/db`
|
||||
- Affected code: `src/processor/heartbeatProcessor.js`, `src/db/databaseManager.js`, `scripts/db/*.sql`, `docs/*`, `test/*`
|
||||
11
openspec/changes/update-heartbeat-arrays-v3/specs/db/spec.md
Normal file
11
openspec/changes/update-heartbeat-arrays-v3/specs/db/spec.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## ADDED Requirements
|
||||
### Requirement: 分区表新增数组列与数组元素索引
|
||||
系统 SHALL 在 `heartbeat.heartbeat_events` 中新增用于存储电力与空调子设备的数组列,并为指定数组列提供数组元素级查询索引。
|
||||
|
||||
#### Scenario: 新增数组列
|
||||
- **WHEN** 部署或升级数据库结构时
|
||||
- **THEN** 表应包含 elec_address、air_address、voltage、ampere、power、phase、energy、sum_energy、state、model、speed、set_temp、now_temp、solenoid_valve
|
||||
|
||||
#### Scenario: 数组元素索引
|
||||
- **WHEN** 需要按 elec_address/air_address/state/model 的数组元素进行查询
|
||||
- **THEN** 数据库应具备 GIN 索引以优化包含类查询
|
||||
@@ -0,0 +1,13 @@
|
||||
## ADDED Requirements
|
||||
### Requirement: 心跳消息扩展数组字段
|
||||
Kafka 心跳消息 SHALL 支持携带电力与空调子设备的数组字段,以便消费端拆列落库与查询优化。
|
||||
|
||||
#### Scenario: 携带 electricity 数组
|
||||
- **WHEN** 生产者需要上报电力设备明细时
|
||||
- **THEN** 消息可选包含 `electricity`(array of object)
|
||||
- **AND** 每个元素包含 address、voltage、ampere、power、phase、energy、sum_energy
|
||||
|
||||
#### Scenario: 携带 air_conditioner 数组
|
||||
- **WHEN** 生产者需要上报空调设备明细时
|
||||
- **THEN** 消息可选包含 `air_conditioner`(array of object)
|
||||
- **AND** 每个元素包含 address、state、model、speed、set_temp、now_temp、solenoid_valve
|
||||
@@ -0,0 +1,19 @@
|
||||
## ADDED Requirements
|
||||
### Requirement: 数组字段聚合为列数组
|
||||
系统 SHALL 将 `electricity[]` 与 `air_conditioner[]` 按原始顺序聚合为数据库写入结构的列数组。
|
||||
|
||||
#### Scenario: electricity 聚合
|
||||
- **WHEN** 输入包含 `electricity` 数组
|
||||
- **THEN** 输出应包含 elec_address[]、voltage[]、ampere[]、power[]、phase[]、energy[]、sum_energy[]
|
||||
- **AND** 各数组下标与输入数组下标一一对应
|
||||
|
||||
#### Scenario: air_conditioner 聚合
|
||||
- **WHEN** 输入包含 `air_conditioner` 数组
|
||||
- **THEN** 输出应包含 air_address[]、state[]、model[]、speed[]、set_temp[]、now_temp[]、solenoid_valve[]
|
||||
- **AND** 各数组下标与输入数组下标一一对应
|
||||
|
||||
#### Scenario: 类型与缺失处理
|
||||
- **WHEN** electricity 或 air_conditioner 存在但不是数组
|
||||
- **THEN** 系统应丢弃该消息并记录错误
|
||||
- **WHEN** 数组元素字段缺失或无法转换
|
||||
- **THEN** 系统应保持长度对齐并写入 null
|
||||
11
openspec/changes/update-heartbeat-arrays-v3/tasks.md
Normal file
11
openspec/changes/update-heartbeat-arrays-v3/tasks.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## 1. Implementation
|
||||
- [ ] 1.1 更新 OpenSpec 增量规范(Kafka/Processor/DB)
|
||||
- [ ] 1.2 数据库脚本与初始化:新增数组列与索引
|
||||
- [ ] 1.3 Processor:数组字段校验与聚合转换
|
||||
- [ ] 1.4 DB 写入:扩展批量 insert 列与参数
|
||||
- [ ] 1.5 测试:新增单元测试覆盖顺序与类型/缺失处理
|
||||
- [ ] 1.6 文档:更新 producer 与 DB schema
|
||||
|
||||
## 2. Validation
|
||||
- [ ] 2.1 运行单元测试与 lint
|
||||
- [ ] 2.2 在可用 PostgreSQL 环境执行冒烟(含数组列插入)
|
||||
@@ -58,6 +58,21 @@
|
||||
- **THEN** 系统应能够自动创建对应日分区或确保分区被预创建
|
||||
- **AND** 不应影响持续写入(高吞吐场景)
|
||||
|
||||
### Requirement: 数组字段存储与索引
|
||||
系统 MUST 支持将电力与空调子设备数据以数组列形式存储,并为指定数组列建立针对元素查询的索引。
|
||||
|
||||
#### Scenario: 新增数组列用于存储电力与空调子设备数据
|
||||
- **WHEN** 系统初始化 v2 心跳明细表结构时
|
||||
- **THEN** 表结构应包含以下新增列:
|
||||
- elec_address(text[])
|
||||
- air_address(text[])
|
||||
- voltage(double precision[])、ampere(double precision[])、power(double precision[])、phase(text[])、energy(double precision[])、sum_energy(double precision[])
|
||||
- state(int2[])、model(int2[])、speed(int2[])、set_temp(int2[])、now_temp(int2[])、solenoid_valve(int2[])
|
||||
|
||||
#### Scenario: 针对数组元素的索引
|
||||
- **WHEN** 对 elec_address、air_address、state、model 执行“元素包含”类查询时
|
||||
- **THEN** 系统应提供 GIN 索引以优化查询
|
||||
|
||||
### Requirement: 数据查询支持
|
||||
系统 MUST 支持基本的数据查询操作,用于监控和调试。
|
||||
|
||||
|
||||
@@ -53,6 +53,32 @@ Kafka 心跳消息 MUST 包含数据库落库所需的必填字段,并采用 U
|
||||
- **THEN** 消息 value 应为 JSON(UTF-8)
|
||||
- **AND** 至少包含 ts_ms、hotel_id、room_id、device_id、ip、power_state、guest_type、cardless_state、service_mask、pms_state、carbon_state、device_count、comm_seq
|
||||
- **AND** 可选包含 extra(json object)
|
||||
- **AND** 可选包含 electricity(array of object)
|
||||
- **AND** 可选包含 air_conditioner(array of object)
|
||||
|
||||
#### Scenario: electricity 数组字段结构
|
||||
- **WHEN** 生产者在心跳消息中携带 electricity 字段时
|
||||
- **THEN** electricity MUST 为数组
|
||||
- **AND** 数组每个元素 MUST 为对象,包含:
|
||||
- address(string,设备地址)
|
||||
- voltage(double,电压)
|
||||
- ampere(double,电流)
|
||||
- power(double,功率)
|
||||
- phase(string,相位)
|
||||
- energy(double,能耗)
|
||||
- sum_energy(double,总能耗)
|
||||
|
||||
#### Scenario: air_conditioner 数组字段结构
|
||||
- **WHEN** 生产者在心跳消息中携带 air_conditioner 字段时
|
||||
- **THEN** air_conditioner MUST 为数组
|
||||
- **AND** 数组每个元素 MUST 为对象,包含:
|
||||
- address(string,设备地址)
|
||||
- state(int2,开关状态)
|
||||
- model(int2,运行模式)
|
||||
- speed(int2,风速设置)
|
||||
- set_temp(int2,设定温度)
|
||||
- now_temp(int2,当前温度)
|
||||
- solenoid_valve(int2,电磁阀门状态)
|
||||
|
||||
### Requirement: 分区键友好的 Kafka Key
|
||||
系统 MUST 支持使用 `hotel_id:device_id` 作为 Kafka message key 以获得更好的分区与有序性。
|
||||
|
||||
@@ -55,6 +55,29 @@
|
||||
- **WHEN** 心跳数据缺失必填字段时
|
||||
- **THEN** 系统应判定为无效数据并丢弃
|
||||
|
||||
### Requirement: 数组字段聚合转换
|
||||
系统 MUST 支持将 electricity[] 与 air_conditioner[] 的对象数组聚合为数据库的“列数组”,并保持原始顺序一致性。
|
||||
|
||||
#### Scenario: electricity 数组聚合为列数组
|
||||
- **WHEN** 心跳数据包含 electricity(对象数组)时
|
||||
- **THEN** 系统应按输入数组原始顺序提取并聚合为:
|
||||
- elec_address[]、voltage[]、ampere[]、power[]、phase[]、energy[]、sum_energy[]
|
||||
- **AND** 同一条心跳记录内,上述各数组下标必须与输入 electricity 的下标一一对应
|
||||
|
||||
#### Scenario: air_conditioner 数组聚合为列数组
|
||||
- **WHEN** 心跳数据包含 air_conditioner(对象数组)时
|
||||
- **THEN** 系统应按输入数组原始顺序提取并聚合为:
|
||||
- air_address[]、state[]、model[]、speed[]、set_temp[]、now_temp[]、solenoid_valve[]
|
||||
- **AND** 同一条心跳记录内,上述各数组下标必须与输入 air_conditioner 的下标一一对应
|
||||
|
||||
#### Scenario: 数组字段缺失与类型校验
|
||||
- **WHEN** electricity 或 air_conditioner 字段存在但类型不为数组时
|
||||
- **THEN** 系统应判定该条消息为无效并丢弃
|
||||
- **AND** 记录错误日志
|
||||
- **WHEN** 数组元素字段缺失或类型不匹配但消息其余必填字段有效时
|
||||
- **THEN** 系统应保持数组长度对齐,并对无法转换的单元写入 null
|
||||
- **AND** 不应破坏其余字段的写入
|
||||
|
||||
### Requirement: 批量处理支持
|
||||
系统 MUST 支持批量处理心跳数据,提高处理效率。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user